深度优先与广度优先
如果多继承是菱形继承,经典类与新式类的属性查找顺序不一样:
经典类:深度优先,会在检索第一条分支的时候就直接一条道走到黑,即会检索共同的父类
新式类:广度优先,会在检索最后一条分支的才会检索共同的父类
class A(object):
def test(self):
print('from A')
class B(A):
# def test(self):
# print('from B')
pass
class C(A):
def test(self):
print('from C')
class D(B):
# def test(self):
# print('from D')
pass
class E(C):
def test(self):
print('from E')
class F(D, E):
# def test(self):
# print('from F')
pass
f1 = F()
f1.test()
# print(F.__mro__) # 只有新式才有这个属性可以查看线性列表,经典类没有这个属性
# 新式类继承顺序:F->D->B->E->C->A
# 经典类继承顺序:F->D->B->A->E->C
# python3中统一都是新式类
# python2中才分新式类与经典类
'''
from E
'''
Mixins机制
Mixins机制核心:就是在多继承背景下尽可能地提升多继承的可读性
简单来说Mixins机制指的是子类混合(mixin)不同类的功能,而这些类采用统一的命名规范(例如Mixin后缀),以此标识这些类只是用来混合功能的,并不是用来标识子类的从属"is-a"关系的,所以Mixins机制本质仍是多继承,但同样遵守”is-a”关系,如下:
class Vehicle:
pass
class FlyableMixin:
def fly(self):
pass
class CivilAircraft(FlyableMixin, Vehicle): # 民航飞机
pass
class Helicopter(FlyableMixin, Vehicle): # 直升飞机
pass
class Car(Vehicle): # 汽车
pass
可以看到,上面的CivilAircraft、Helicopter类实现了多继承,不过它继承的第一个类我们起名为FlyableMixin,而不是Flyable,这个并不影响功能,但是会告诉后来读代码的人,这个类是一个Mixin类,表示混入(mix-in),这种命名方式就是用来明确地告诉别人(python语言惯用的手法),这个类是作为功能添加到子类中,而不是作为父类,它的作用同Java中的接口。所以从含义上理解,CivilAircraft、Helicopter类都只是一个Vehicle,而不是一个飞行器。
使用Mixin类实现多重继承要非常小心:
-
首先它必须表示
某一种功能,而不是某个物品,python 对于mixin类的命名方式一般以 Mixin, able, ible 为后缀 -
其次它必须责任单一,如果有多个功能,那就写多个Mixin类,一个类可以继承多个Mixin,为了保证遵循继承的“is-a”原则,只能继承一个标识其归属含义的父类
-
然后,它不依赖于子类的实现
-
最后,子类即便没有继承这个Mixin类,也照样可以工作,就是缺少了某个功能。(比如飞机照样可以载客,就是不能飞了)
在子类派生的新方法中如何重用父类的功能
方法一:指名道姓
指名道姓调用某一类下的函数——>不依赖继承关系
class People:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def f1(self):
print('%s say hello' % self.name)
class Teacher(People):
def __init__(self, name, age, sex, level, salary):
People.__init__(self, name, age, sex)
self.level = level
self.salary = salary
方法二:super方法
super( )调用父类提供给自己的方法——>严格依赖继承关系
super( )会得到一个特殊的对象,该对象会参照发起属性查找类的mro,去当前类的父类中访问属性
class People:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def f1(self):
print('%s say hello' % self.name)
class Teacher(People):
def __init__(self, name, age, sex, level, salary):
super().__init__(name, age, sex)
self.level = level
self.salary = salary
Teacher1 = Teacher('egon', 18, 'male', 10, 3000)
print(Teacher1.__dict__)
'''
{'name': 'egon', 'age': 18, 'sex': 'male', 'level': 10, 'salary': 3000}
'''