先看一个「菱形继承」的例子:
图1菱形继承
如果 x 是 D 的一个实例,那么 x.show() 到底会调用哪个 show 方法呢?如果按照 [D, B, A, C] 的搜索顺序,那么 x.show() 会调用 A.show();如果按照 [D, B, C, A] 的搜索顺序,那么 x.show() 会调用 C.show()。由此可见,MRO 是把类的继承关系线性化的一个过程,而线性化方式决定了程序运行过程中具体会调用哪个方法。既然如此,那什么样的 MRO 才是最合理的?Python 中又是如何实现的呢?
Python 2.3以后采用了 C3 方法来确定方法解析顺序。它也是 Python 3 唯一支持的方式
一个类C3线性化的是这个类,再加上它的各个父类的线性化与各个父类形成列表的唯一合并的结果。父类列表作为合并过程的最后实参,保持了直接父类的本地前趋序。
各个父类的线性化与各个父类形成列表的合并算法,首先选择不出现在各个列表的尾部(指除了第一个元素外的其他元素)的第一个元素,该元素可能同时出现在多个列表的头部。被选中元素从各个列表中删除并追加到输出列表中。这个选择再删除、追加元素的过程迭代下去直到各个列表被耗尽。如果在某个时候无法选出元素,说明这个类继承体系的依赖序是不一致的,因而无法线性化。
我们把类 C 的线性化(MRO)记为 L[C] = [C1, C2,…,CN]。其中 C1 称为 L[C] 的头,其余元素 [C2,…,CN] 称为尾。如果一个类 C 继承自基类 B1、B2、……、BN,那么我们可以根据以下两步计算出 L[C]:
L[object] = [object]
L[C(B1…BN)] = [C] + merge(L[B1]…L[BN], [B1],BN])
这里的关键在于 merge,其输入是一组列表,按照如下方式输出一个列表:
图1中各个类的线性化计算
L[A] := [A,O]
L[B] := [B] + merge(L[A])
= [B] + merge([A,O],[A])
= [B,A] + merge([O])
= [B,A,O]
L[C] := [C,A,O]
L[D] := [D] + merge(L[B],L[C],[B],[C])
= [D] + merge([B,A,O],[C,A,O],[B],[C])
= [D,B] + merge([A,O],[C,A,O],[C])
= [D,B,C] + merge([A,O],[A,O])
= [D,B,C,A] + merge([O],[O])
= [D,B,C,A]
所以x.show()会调用C.show()
图2中各个类的线性化计算
L(O) := [O]
L(A) := [A] + merge(L(O), [O])
= [A] + merge([O], [O])
= [A, O]
L(B) := [B, O]
L(D) := [D, O]
L(E) := [E, O]
L(K1) := [K1] + merge(L(A), L(B), L(C), [A],[B],[C])
= [K1] + merge([A, O], [B, O], [C, O], [A],[B], [C])
= [K1, A] + merge([O], [B, O], [C, O], [B], [C])
= [K1, A, B] + merge([O], [O], [C, O], [C])
= [K1, A, B, C] + merge([O], [O], [O])
= [K1, A, B, C, O]
L(K2) := [K2] + merge(L(D), L(B), L(E), [D],[B],[E]])
= [K2] + merge([D, O], [B, O], [E, O], [D] ,[B], [E]])
= [K2, D] + merge([O], [B, O], [E, O], [B], [E])
= [K2, D, B] + merge([O], [O], [E, O], [E])
= [K2, D, B, E] + merge([O], [O], [O])
= [K2, D, B, E, O]
L(K3) := [K3] + merge(L(D), L(A), [D], [A])
= [K3] + merge([D, O], [A, O], [D],[A])
= [K3, D] + merge([O], [A, O], [A])
= [K3, D, A] + merge([O], [O])
= [K3, D, A, O]
L(Z) := [Z] + merge(L(K1), L(K2), L(K3), [K1], [K2], [K3])
= [Z] + merge([K1, A, B, C, O], [K2, D, B, E, O], [K3, D, A, O], [K1], [K2], [K3])
= [Z, K1] + merge([A, B, C, O], [K2, D, B, E, O], [K3, D, A, O], [K2], [K3])
= [Z, K1, K2] + merge([A, B, C, O], [D, B, E, O], [K3, D, A, O], [K3])
= [Z, K1, K2, K3] + merge([A, B, C, O], [D, B, E, O], [D, A, O])
= [Z, K1, K2, K3, D] + merge([A, B, C, O], [B, E, O], [A, O])
= [Z, K1, K2, K3, D, A] + merge([B, C, O], [B, E, O], [O])
= [Z, K1, K2, K3, D, A, B] + merge([C, O], [E, O], [O])
= [Z, K1, K2, K3, D, A, B, C] + merge([O], [E, O], [O])
= [Z, K1, K2, K3, D, A, B, C, E] + merge([O], [O], [O])
= [Z, K1, K2, K3, D, A, B, C, E, O]
多重继承的执行顺序,请解答以下输出结果是什么?并解释。
class A(object):
def __init__(self):
print('A')
super(A, self).__init__()
class B(object):
def __init__(self):
print('B')
super(B, self).__init__()
class C(A):
def __init__(self):
print('C')
super(C, self).__init__()
class D(A):
def __init__(self):
print('D')
super(D, self).__init__()
class E(B, C):
def __init__(self):
print('E')
super(E, self).__init__()
class F(C, B, D):
def __init__(self):
print('F')
super(F, self).__init__()
class G(D, B):
def __init__(self):
print('G')
super(G, self).__init__()
if __name__ == '__main__':
g = G()
f = F()
C3线性化计算
L[A] := [A,O]
L[B] := [B,O]
L[C] := [C,A,O]
L[D] := [D,A,O]
L[E] := [E] + merge(L[B],L[C],[B],[C])
= [E] + merge([B,O],[C,A,O],[B],[C])
= [E,B] + merge([O],[C,A,O],[C])
= [E,B,C] + merge([O],[A,O])
= [E,B,C,A] + merge([O],[O])
= [E,B,C,A,O]
L[F] := [F] + merge(L[C],L[B],L[D],[C],[B],[D])
= [F] + merge([C,A,O],[B,O],[D,A,O],[C],[B],[D])
= [F,C] + merge([A,O],[B,O],[D,A,O],[B],[D])
= [F,C,B] + merge([A,O],[O],[D,A,O],[D])
= [F,C,B,D] + merge([A,O],[O],[A,O])
= [F,C,B,D,A] + merge([O],[O],[O])
= [F,C,B,D,A,O]
L[G] := [G] + merge(L[D],L[B],[D],[B])
= [G] + merge([D,A,O],[B,O],[D],[B])
= [G,D] + merge([A,O],[B,O],[B])
= [G,D,A] + merge([O],[B,O],[B])
= [G,D,A,B] + merge([O],[O],[O])
= [G,D,A,B,O]
f=F()
执行结果
F
C
B
D
A
g=G()
执行结果
G
D
A
B