Python多继承的特殊例子(C3算法)

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python多继承的特殊例子(C3算法)相关的知识,希望对你有一定的参考价值。

之前看课程的时候一直说python3新式类中多继承顺序解析的时候,用的是广度优先算法,再之后就看到了下面这个例子

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

继承关系如图

如果按照讲的广度优先,那么E的搜索顺序,就是EBCA;F的搜索顺序就是FCBDA;G的顺序就是GDBA
其实想到这里的时候就能感觉到有问题,因为从上到下看B是和A是一层的,而从下到上看,可能B就会和C、D划到一层
所以感觉应该问题没有这么简单,所以打出来搜索顺序看一下:

	print(G.__mro__)
    # (<class '__main__.G'>, <class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
    print(F.__mro__)
    # (<class '__main__.F'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
    print(E.__mro__)
    # (<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

可以看到G的搜索顺序,是GDAB,这是为什么呢,搜索到D的时候向深度走了一层,才跳到了B,和广度优先的认知不太一样;而如果按照这种方法走的话,F的顺序又为啥不是先C后A再B这样呢
明显广度优先是有问题的
那么到底是按照什么算法寻找的呢

可以看下这篇文章:https://hanjianwei.com/2013/07/25/python-mro/
用的是C3算法,其实也比较好理解
在merge的时候,每次都是将列表头取出,然后查看这表头是否在其他列表的尾部,如果在,那么就跳过,取下一个列表的头部重复这个判断;如果不在,加入最终的顺序列表
用这个算法计算上面那个例子结果如下:
主要关注F的顺序,在判断A的时候,因为A也出现在了后面列表的尾部,所以跳过了A,先搜索了B和D

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] 

以上是关于Python多继承的特殊例子(C3算法)的主要内容,如果未能解决你的问题,请参考以下文章

Python 中多继承 C3-MRO 算法的剖析

python多继承之C3算法

Python的多继承问题-MRO和C3算法

Python多继承解析顺序的C3线性算法流程解析

python D20 多继承C3算法super()

python的继承,多继承,经典类的MRO,新式类的MRO,C3算法,super