继承
继承用来解决类和类之间的代码冗余问题,是一种创建新类的方式,python支持多继承,即新建的类可以继承一个或多个父类,
在python3中新建一个类,如果这个类没有继承任何类,默认它会继承object类,继承了object类的类及其子类,子子类,叫新式类
object类是python解释器内置的类
属性查找
单继承:有了继承关系,对象在查找属性时,先从对象自己的__dict__中找,如果没有则去对象的类中找,然后再去父类中找……
class Foo:
def f1(self):
print('Foo.f1')
def f2(self):
print('Foo.f2')
self.f1()
class Bar(Foo):
def f1(self):
print('bar.f1')
b=Bar()
b.f2()
'''
Foo.f2
bar.f1
'''
#要访问Foo.f1
class Foo:
def __f1(self):
print('Foo.f1')
def f2(self):
print('Foo.f2')
# 相当于self._Foo__f1()
self.__f1()
class Bar(Foo):
# 相当于self._Bar__f1()
def __f1(self):
print('bar.f1')
b = Bar()
b.f2()
Foo.f2(b) #类调用自己的方法,要正常传入参数
'''
Foo.f2
Foo.f1
Foo.f2
Foo.f1
'''
不建议使用多继承,可能会引发菱形问题,扩展性变差
多继承是非菱形继承:经典类和新式类的查找顺序一样,类和类的对象访问属性时都是参照该类的方法解析顺序MRO列表
多继承是菱形继承,经典类和新式类的查找顺序不一样,经典类是深度优先,即在第一条线中就去共同的类中查找
新式类是广度优先,即在最后一条线路才去共同的类中查找
新式类内置了mro()方法,经典类没有这个方法
#菱形问题
class A(object):
def test(self):
print('from A')
class B(A):
def test(self):
print('from B')
class C(A):
def test(self):
print('from C')
class D(C,B):
pass
print(D.mro())
obj = D()
obj.test()
'''
[<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
from C
'''
'''
1.子类会先于父类被检查
2.多个父类会根据它们在mro列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
'''
1.由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去,
2.由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去,
Mixin机制
CivilAircraft类和Helicopter类的父类只能有一个,那就是Vehicle类,这个父类有所有子类共同的东西,并且它表示一个事物,子类在继承这个类时,要将其放在括号内的最右边
FlyableMixin类的命名规范:在Flyable后面加上Mixin,这个类里面只定义一种功能(不是只定义一个函数),如果有多种功能,需要定义多个这样的类,这种功能是独立的,这种功能只是某些子类才有的,某个子类继承了这个Mixin类,就有了这个功能,
class Vehicle: # 交通工具
pass
class FlyableMixin:
def fly(self):
'''
飞行功能相应的代码
'''
print("I am flying")
class CivilAircraft(FlyableMixin, Vehicle): # 民航飞机
pass
class Helicopter(FlyableMixin, Vehicle): # 直升飞机
pass
class Car(Vehicle): # 汽车
pass
# ps: 采用某种规范(如命名规范)来解决具体的问题是python惯用的套路
在子类派生的新方法中重用父类的功能
在一个类的方法中重用另一个类的功能
这种调用方式不依赖继承关系,因为指明了调用哪个类的哪个方法
类名.类中的方法名
Oldboy._init_(self,name,age,sex)
class OldBoy:
school = 'OldBoy'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class Student(OldBoy):
pass
#Teacher类继不继承OldBoy类,结果是一样的
class Teacher():
def __init__(self, name, age, sex, salary, level):
OldBoy.__init__(self,name,age,sex) #类调用自己的函数不会有绑定方法的效果,即不会把空对象作为参数传入
self.salary = salary
self.level = level
teacher1 = Teacher('egon', 18, 'male', 3000, 10)
print(teacher1.__dict__)
'''
{'name': 'egon', 'age': 18, 'sex': 'male', 'salary': 3000, 'level': 10}
'''
super方法依赖继承关系
调用super方法会得到一个特殊的对象,在有直接继承关系时,该对象专门用来引用父类的属性,该对象会参照发起属性查找的类(不一定是super方法所在的类)的MRO列表,去当前类(super方法所在的类,因为发起属性查找的类要重用父类的功能,找到super方法所在的类时,没有这个功能)的下一个类(因为有继承关系,下一个类其实就是父类)中查找属性,
class Oldboy:
school='Oldboy'
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
class Student(Oldboy):
pass
class Teacher(Oldboy):
def __init__(self,name,age,sex,salary,level):
# 调用super方法会得到一个特殊的对象,对象再调用方法,会自动把对象传进去,不需要写self参数
super().__init__(name,age,sex) #python3中的写法
#super(Teacher,self).__init__(name,age,sex) #python2中的写法,和上一句等价,super用来获得父类的方法
self.salary = salary
self.level = level
teacher1=Teacher('egon',18,'male',3000,10)
print(Teacher.mro())
print(teacher1.__dict__)
'''
[<class '__main__.Teacher'>, <class '__main__.OldBoy'>, <class 'object'>]
{'name': 'egon', 'age': 18, 'sex': 'male', 'salary': 3000, 'level': 10}
'''
super()是依赖于继承的,即使没有直接继承关系,super()仍然会按照MRO列表继续往后查找(以下例子)
调用super方法会得到一个特殊的对象,在没有直接继承关系时,该对象专门用来引用别类的属性,该对象会参照发起属性查找的类(不一定是super方法所在的类)的MRO列表,去当前类(super方法所在的类,因为发起属性查找类要重用别的类的功能,找到super方法所在的类时,没有这个功能)的下一个类中查找属性,
# A没有继承B
class A:
def test(self):
super().test()
class B:
def test(self):
print('from B')
class C(A,B):
pass
print(C.mro())
print(A.mro())
obj=C()
obj.test()
'''
# 发起属性查找的类是C
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
[<class '__main__.A'>, <class 'object'>]
from B
'''
组合
在一个类中以另外一个类的对象作为数据属性,称为类的组合
多态
多态性的本质在于不同的类中定义有相同的方法名,这样我们就可以不考虑类而统一用一种方式去使用对象
#鸭子类型
#二者看起来都像文件,因而就可以当文件一样去用,然而它们并没有直接的关系
class Txt: #Txt类有两个与文件类型同名的方法,即read和write
def read(self):
pass
def write(self):
pass
class Disk: #Disk类也有两个与文件类型同名的方法:read和write
def read(self):
pass
def write(self):
pass
#把对象的使用方法统一成一种,即定义一个统一的接口来使用
def read(obj):
obj.read()
def write(obj):
obj.write()
txt1 = Txt()
disk = Disk()
read(txt1)
write(txt1)
read(disk)
write(disk)