python 多重继承
当前代码还没错误·
class X(object): pass
class Y(object): pass
class A(X, Y): pass
class B(Y, X): pass
如果加上以下的类 C继承 会出现错误
TypeError Traceback (most recent call last)
<ipython-input-144-1bfe1fb4b3ba> in <module>()
3 class A(X, Y): pass
4 class B(Y, X): pass
----> 5 class C(A, B): pass
6
TypeError: Cannot create a consistent method resolution
order (MRO) for bases X, Y
因为C 类具有二义性的继承关系
多重继承具体分析算法
1,C 类的线性化 结果记作 L[C] = [C1,C2,…CN] , 其中 C1 称为 L[C] 的头,其余元素 [C2,…,CN] 称为尾 这里的尾部定义和常识不同,后面会用到,!!
2,如果一个类 C 继承自基类 B1、B2、……、BN
L[object] = [object]
L[C(B1…BN)] = [C] + merge(L[B1]…L[BN], [B1]…[BN])
merge 输入一组列表,输出是一个列表:
- 检查第一个列表的头元素(如 L[B1] 的头),记作 H。
- 若 H未出现在其它列表的尾部,则将其输出,并将其从所有列表中删除,然后回到步骤1;否则,取出下一个列表的头部记作 H,继续该步骤。
- 重复上述步骤,直至列表为空或者不能再找出可以输出的元素。如果是前一种情况,则算法结束;如果是后一种情况,说明无法构建继承关系,Python 会抛出异常。
例如 上面图中的 A
L[object] = [object]
L[X] = [X, object]
L[Y] = [Y, object]
L[A] = [A] + merge(L[X], L[Y], [X], [Y])
= [A] + merge([X, object], [Y, object], [X,Y]) # X 未出现在其他的列表尾部
= [A, X] + merge([object], [Y, object], [Y])。# object 出现在第二个列表尾部
= [A, X, Y] + merge([object], [object]) # Y 未出现在尾部
= [A, X, Y, object] # 列表为空
L[B] = [B, Y, X, object]
计算 L[C] 的 线性化结果
L[C] = [C] + merge(L[A], L[B], [A], [B])
= [C] + merge([A, X, Y, object], [B, Y, X, object], [A,B])
= [C, A] + merge([X, Y, object], [B, Y, X, object], [B])
= [C, A, B] + merge([X, Y, object], [Y, X, object]) # X 虽然是第一个列表的头,但是它出现在了第二个列表的尾部;Y 虽然是第二个列表的头,但是它出现在了第一个列表的尾部 没办法继续计算
此时你可能会有这样的疑问“为什么X 是第二个列表的尾部?Y 为什么是第一个列表的尾部 ?”
如果有此疑问请看上面对于尾部的定义
L[C] 最后没办法输出,但是剩余列表不为空, 所以对于C类无法构建一个没有二义性的继承关系
python 多重继承的方法解析顺序
class A:
def say(self):
print("A Hello:", self)
class B(A):
def eat(self):
print("B Eating:", self)
class C(A):
def eat(self):
print("C Eating:", self)
class D(B, C):
def say(self):
super().say()
print("D Hello:", self)
def dinner(self):
self.say()
super().say()
self.eat()
super().eat()
C.eat(self)
Python 能区分 d.eat() 调用的是哪个方法, 是因为 Python 会按照特定的顺序遍历继承图,python3就是广度优先。 这个顺序叫方法解析顺序( Method Resolution Order, MRO)。 类都有一个名为 __mro__ 的属性, 它的值是一个元组, 按照方法解析顺序列出各个超类, 从当前类一直向上, 直到object 类。
D 类的 __mro__ 属性如下 :
>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
图例
在python3中调用D继承的save方法 搜索按广度优先 路径D->B->C->A, 执行C中save