类、对象:
- 类:抽象的
- 对象:具体的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
class Person: # 类名 def __init__(self, name, hp, aggr, gender): # __init__为初始化方法 self.name = name self.hp = hp self.aggr = aggr self.gender = gender def walk(self, n): # 定义方法,一般情况下必须传self参数,且必须写在第一个;后面还可以传其他参数,想传多少就多少 print("{}走了{}步".format(self.name, n))p = Person("王者", "100", "5", "男") # 对象 = 类(参数),这个过程叫实例化print(p.name) # 查看属性值print(p.__dict__) # 查看所有属性p.walk(10) # 调用这个对象拥有的方法
类有静态属性和方法,类中的静态属性和方法可以被对象和类调用。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
class Person(object): money = 0 def work(self): Person.money += 100mother = Person()father = Person()mother.work()father.work()print(Person.money) #200
类的组合:在一个类中以另外一个类的对象作为数据属性
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
class Car: """一次模拟汽车的简单尝试""" def __init__(self, make, model, year): self.make = make self.model = model self.year = yearclass Battery: """一次模拟电动汽车电瓶的简单尝试""" def __init__(self, battery_size=70): """初始化电瓶的属性""" self.battery_size = battery_size def describe_battery(self): """打印一条描述电瓶容量的消息""" print("This car has a " + str(self.battery_size) + "-kWh battery.")class ElectricCar(Car): """电动汽车特殊之处""" def __init__(self, make, model, year): """初始化父类的属性,再初始化电动汽车特有的属性""" super().__init__(make, model, year) self.battery = Battery()my_tesla = ElectricCar("tesla", "model s", 2016)my_tesla.battery.describe_battery() #This car has a 70-kWh battery.
面向对象三大特性:继承、多态、封装
继承
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又称为基类或超类,新建的类这时可称为子类或派生类
python中类的继承分为:单继承和多继承
一个类可以被多个类继承
一个类可以继承多个父类(python独有)![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
class A(object): # 定义父类 passclass B(object): # 定义父类 passclass C(A): # 单继承,父类是A,子类是C passclass D(A,B): # 多继承(python独有),用逗号分隔开多个继承的类 pass########## 查看继承 ########### __base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类print(D.__base__) #print(D.__bases__) # ( , )#在python3中,没有继承父类就默认继承objectprint(A.__bases__) # ( ,)
派生
- 父类中没有的属性,在子类有,叫做派生属性
- 父类中没有的方法,在子类有,叫做派生方法
注意:
子类可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),一旦重新定义了自己的属性且与父类重名,调用时就以自己为准;
要是子类的对象调用属性,子类中有的名字就用子类的, 子类中没有才找父类的, 如果父类也没有就报错在python3中,子类执行父类的方法也可以直接用super方法(super方法只在python3中存在)
class Base1(object): def func(self): print("Base1.func")class Base2(object): def func(self): print("Base2.func")class Foo(Base1, Base2): def func(self): # 方式一:根据mro的顺序执行方法 super().func() # Base1.func super(Foo, self).func() # Base1.func # 方式二:主动执行父类类的方法 Base2.func(self) # Base2.func print("Foo.func")obj = Foo()obj.func() # Foo.funcsuper(Foo, obj).func() # Base1.func 在类外调用父类方法print(Foo.mro()) # [, , , ]
继承顺序:
单继承:子类有的用子类,子类没有就用父类
多继承: 经典类中:深度优先 新式类中:广度优先python2.7中: 经典类、新式类共存,新式类要继承object
python3中: 只有新式类,默认继承objectsuper的本质(python3才有,即只有新式类,广度优先):不是单纯找父类,而是根据调用者的节点位置的广度优先顺序来的
class A(object): def func(self): print("A")class B(A): def func(self): super().func() print("B")class C(A): def func(self): super().func() print("C")class D(B,C): def func(self): super().func() print("D")d = D()d.func()print(D.mro()) # mro()方法可查看类的继承顺序# [, , , , ]
多态
多态指的是一类事物有多种形态
动物有多种形态:人、狗、猪![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
import abcclass Animal(metaclass=abc.ABCMeta): # 动物类 @abc.abstractmethod def talk(self): passclass People(Animal): # 动物的形态之一:人 def talk(self): print("你好!")class Dog(Animal): # 动物的形态之二:狗 def talk(self): print("旺旺!")class Cat(Animal): # 动物的形态之三:猫 def talk(self): print("喵喵!")
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
# 类List与类Tuple都有相似的方法,那么这两个类就是鸭子类型,都可以使用len()方法,而不需要像其他语言一样告诉len()自己是什么类型# 在强类型语言中,叫多态# 在python中,叫鸭子类型class List(object): def __len__(self): passclass Tuple(object): def __len__(self): passdef len(obj): return obj.__len__()l = List() # 或者T = Tuple()len(l)
封装
隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处:
1.将变化隔离; 2.便于使用; 3.提高复用性; 4.提高安全性。封装原则:
1.将不需要对外提供的内容都隐藏起来; 2.把属性都隐藏,提供公共方法对其访问。在python中用双下划线开头的方式将属性隐藏起来(设置成私有属性)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
class Person: __country = "china" # 私有静态属性 def __init__(self, name, age): self.name = name self.__age = age # 私有实例属性 def __get_age(self): # 私有方法 return self.__age def func(self): return self.__get_age() # 调用私有xx的正确方式p = Person("pd", 18)print(p.func()) # 正确使用方式# print(p._Person__age) # 对象._类名__属性名(不建议这样使用!!!)
封装与扩展性
封装在于明确区分内外,使得类设计者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
class Person(object): def __init__(self, name, age): self.name = name self.__age = age def get_age(self): return self.__age def set_age(self, n): if 0 < n and n.isdigit(): self.__age = n else: return "年龄不合法"p = Person("pd", 18)print(p.get_age()) # 18print(p.set_age(-18)) # 年龄不合法
会用到私有的这个概念的场景:
1.隐藏一个属性,不让类的外部直接调用
2.保护一个属性,不让属性随意被改变 3.保护一个属性,不被子类继承小结
接口类、抽象类:
python中没有接口类,有抽象类,abc模块中的metaclass = ABCMeta,@abstructmethod 本质是做代码规范用的,希望在子类中实现和父类方法名字完全一样的方法接口类与抽象类的区别:
在java的角度上看是有区别的 java没有多继承,所以为了接口隔离原则,设计了接口这个概念,以便实现多继承; java本来就支持单继承,所以就有了抽象类。 python既支持单继承也支持多继承,所以对于接口类和抽象类的区别就没有那么明显;python中没有内置接口类多态与鸭子类型:
多态 --> python天生支持多态 鸭子类型 --> 不依赖父类的情况下实现两个相似的类中的同名方法