多继承
Python2版本
class A(object) ---> 新式类
class B ---> 经典类
Python3版本
默认都是新式类
经典类和新式类的不同在于多继承时继承的顺序不同
经典类 ---> 深度优先
新式类 ---> c3算法
class Immortal: def __init__(self): self.age = "长生不老" def fly(self): print("神仙都会飞") def eat(self): print("神仙也要吃东西") class Monkey: def climb(self): print("猴子都会爬树") def eat(self): print("猴子也要进食") class Monkey_sun(Immortal, Monkey): pass sun = Monkey_sun() sun.fly() # 神仙都会飞 sun.climb() # 猴子都会爬树 sun.eat() # 神仙也要吃东西 # --->先计算Monkey_sun(Immortal, Monkey)中最左边的父类
# 前提是Python2版本
# 经典类的多继承
class A: pass class B(A): pass class C(A): pass class D(B, C): pass class E: pass class F(D, E): pass class G(F, D): pass class H: pass class Foo(H, G): pass # 深度优先,从左到右,一条路走到底
继承关系图已经有了. 那如何进⾏查找呢? 记住⼀个原则. 在经典类中采⽤的是深度优先,遍历⽅案. 什么是深度优先. 就是⼀条路走到头. 然后再回来. 继续找下⼀个.
如图看出是按照123456这样的顺序来送. 这就叫深度优先遍历.
所以上面Python2版本中的多继承的顺序为:
类的MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C.
# 新式类的多继承 # mro序列 # MRO是一个有序列表L,在类被创建时就计算出来。 # 通用计算公式为: # mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), # mro(Base2), [ Base1, Base2] )(其中Child继承自Base1, Base2) class A: pass class B: pass class C(B, A): pass # mro(C) = mro(C(B, A)) = [C] + merge(mro(A), mro(B), [B, A])
如果继承至一个基类:class B(A)
这时B的mro序列为:
mro( B ) = mro( B(A) )
= [B] + merge( mro(A) + [A] )
= [B] + merge( [A] + [A] )
= [B,A]
如果继承至多个基类:class B(A1, A2, A3 …)
这时B的mro序列
mro(B) = mro( B(A1, A2, A3 …) )
= [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
= ...
计算结果为列表,列表中至少有一个元素即类自己
如上述示例[A1,A2,A3]。merge操作是C3算法的核心。
表头和表尾
表头:
列表的第一个元素
表尾:
列表中表头以外的元素集合(可以为空)
示例
列表:[A, B, C]
表头是A,表尾是B和C
如计算merge( [E,O], [C,E,F,O], [C] )
有三个列表 : ① ② ③
1 merge不为空,取出第一个列表列表①的表头E,进行判断
各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
2 取出列表②的表头C,进行判断
C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
3 进行下一次新的merge操作 ......
举例:
# 上面的字母代表类 # 那么,整个多继承关系相当于下面 class O: pass class D(O): pass class E(O): pass class F(O): pass class B(D,E): pass class C(E,F): pass class A(B, C): pass obj = A() # 这里假设每个类中都有一个 func(),现在要算继承顺序
下面是详细推导过程
1. 首先列出 mor 等式 (最开始,类A继承了类B和类C)
mro(A(B,C)) = [A] + merge(mro(B),mro(C),[B,C])
2. 写出 mor(B)的结果(看上面的图)
mro(B) = mro(B(D,E))---> 类B继承了类D和类E
3. 写出 mor(B(D,E)) 的等式
mro(B(D,E)) = [B] + merge(mro(D),mro(E),[D,E])
4. 把 mor(D) 和 mor(E) 的结果写出来
因为类D和类E都只继承一个类O,所以一下就能得出结果
mro(B(D,E)) = [B] + merge([D,O],[E,O],[D,E])
5. 现在开始推导 merge([D,O],[E,O],[D,E]) 的结果
首先,有三个列表,把第一个列表的表头即D取出来,
把剩下的两个列表的表头也去掉,还剩 [O] [O] [E],
这三个列表中都没有D,因此把D加到[B],然后把列表中有D的去掉D
mro(B(D,E)) = [B,D] + merge([O],[E,O],[E])
6. 推导merge([O],[E,O],[E]),把第一个列表的表头O提出来,
三个列表还剩下 [] [O] [], 第二个列表中有O,跳过,
从 ([O],[E,O],[E]) 第二个列表开始推导,把E提出来,
三个列表还剩下 [] [O] [],都没有E,因此把E加到[B,D]
另外,把所有列表中有E的去掉
mro(B(D,E)) = [B,D,E] + merge([O],[O])
7. 剩下[O],[O]结果就直接是O了,因此最后结果如下所示
mro(B(D,E)) = [B,D,E,O]
8. 按照上面方法推导mro(C) = mro(C(E,F)),过程如下:
mro(C) = mro(C(E,F))
mro(C(E,F)) = [C] + merge([E,O],[F,O],[E,F])
mro(C(E,F)) = [C,E] + merge([O],[F,O],[F])
mro(C(E,F)) = [C,E,F] + merge([O],[O])
mro(C(E,F)) = [C,E,F,O]
9. 接下来算总的,方法一样
mro(A(B,C)) = [A] + merge([B,D,E,O],[C,E,F,O],[B,C])
mro(A(B,C)) = [A,B] + merge([D,E,O],[C,E,F,O],[C])
mro(A(B,C)) = [A,B,D] + merge([E,O],[C,E,F,O],[C])
mro(A(B,C)) = [A,B,D,C] + merge([E,O],[E,F,O])
mro(A(B,C)) = [A,B,D,C,E] + merge([O],[F,O])
mro(A(B,C)) = [A,B,D,C,E,F] + merge([O],[O])
mro(A(B,C)) = [A,B,D,C,E,F,O] ---> 最终结果
上面结果即是新式类的继承顺序
# 对于继承中的 super来说,也一样 # super 也遵循 mro 顺序 class O: def func(self): print('in O') class D(O): # pass def func(self): print('in D') class E(O): # pass def func(self): print('in E') class F(O): def func(self): print('in F') class B(D,E): # pass def func(self): print('in B') class C(E,F): # pass def func(self): print('in C') class A(B,C): def func(self): super().func() print('in A') obj = A() obj.func() # in B # in A # mro(A(B,C)) = [A,B,D,C,E,F,O] # 根据上面的结果,如果把类B的 func() 注释掉,即结果变为 # in D # in A # 同理,再把类D的 func() 注释,则结果变为 # in C # in A # 依次类推,因此,super 也遵循 mro 顺序 # 当然,真正做项目时可以直接调用 __mro__ 方法来查询顺序 print(A.__mro__) # (<class '__main__.A'>, <class '__main__.B'>, # <class '__main__.D'>, <class '__main__.C'>, # <class '__main__.E'>, <class '__main__.F'>, # <class '__main__.O'>, <class 'object'>)