Python3多继承时的方法解析顺序

文章目录

    • Python3中使用的MRO
      • C3线性化
      • 线性化计算方法
      • python例子
    • 参考链接

对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于基类,所以在方法调用时就需要对当前类和基类进行搜索以确定方法所在的位置。而搜索的顺序就是所谓的「方法解析顺序」(Method Resolution Order,或MRO)。对于只支持单继承的语言来说,MRO 一般比较简单;而对于 Python 这种支持多继承的语言来说,MRO 就复杂很多。

先看一个「菱形继承」的例子:
Python3多继承时的方法解析顺序_第1张图片
图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 中又是如何实现的呢?

Python3中使用的MRO

Python 2.3以后采用了 C3 方法来确定方法解析顺序。它也是 Python 3 唯一支持的方式

C3线性化

一个类C3线性化的是这个类,再加上它的各个父类的线性化与各个父类形成列表的唯一合并的结果。父类列表作为合并过程的最后实参,保持了直接父类的本地前趋序。
各个父类的线性化与各个父类形成列表的合并算法,首先选择不出现在各个列表的尾部(指除了第一个元素外的其他元素)的第一个元素,该元素可能同时出现在多个列表的头部。被选中元素从各个列表中删除并追加到输出列表中。这个选择再删除、追加元素的过程迭代下去直到各个列表被耗尽。如果在某个时候无法选出元素,说明这个类继承体系的依赖序是不一致的,因而无法线性化。

Python3多继承时的方法解析顺序_第2张图片
图2: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[B1] 的头),记作 H。(列表的尾部是,一个列表中除了头元素外的所有元素)
  2. 若 H 未出现在其它列表的尾部,则将其输出,并将其从所有列表中删除,然后回到步骤1;否则,取出下一个列表的头部记作 H,继续该步骤。
  3. 重复上述步骤,直至列表为空或者不能再找出可以输出的元素。如果是前一种情况,则算法结束;如果是后一种情况,说明无法构建继承关系,Python 会抛出异常。

图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]                                               

python例子

多重继承的执行顺序,请解答以下输出结果是什么?并解释。
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

参考链接

  • Python的方法解析顺序(MRO)
  • C3线性化,维基百科

你可能感兴趣的:(python,python)