Python多继承查找规则:C3算法

Python多继承查找规则:C3算法

Python中在类进行多层继承的情况下,对于子类查找父类的属性和方法并不容易一眼看出来他优先去那个父类里面查找,举个例子来说。

class A1:
   def hello(self):
       print("hello, i am A1")


class A2:
   def hello(self):
       print("hello, i am A2")


class A3:
   def hello(self):
       print("hello, i am A3")


class B1(A1, A2):
   pass


class B2(A2, A3):
   pass


class B3(A3):
   pass


class C(B1, B2, B3):
   pass

test = C()
test.hello()

我们定义了三个继承自Object的类分别是A1,A2,A3.接着定义了B1继承自A1和A2,B2继承自A2,A3,B3继承自A3,最后定义了一个C类继承自B1,B2,B3.然后实例化了一个对象test,调用test的hello方法。

你能一眼看出来这个hello方法是调用的那个父类的方法么?是不是有点困难呢?

答案是:

hello, i am A1

对,它调用的是A1类中的方法。也许你一眼就直接看出来了,但是如果这个继承关系更加复杂呢?是不是难以一眼看穿呢?

这时候可以调用Python的方法mro来查看类的继承关系。

print(C.mro())

结果是:

[<class '__main__.C'>, <class '__main__.B1'>, <class '__main__.A1'>, <class '__main__.B2'>, <class '__main__.A2'>, <class '__main__.B3'>, <class '__main__.A3'>, <class 'object'>]

这样我们可以看到C类向上查询父类的方法和属性的路径,也不难看出为什么会调用A1类的hello方法了。

这样就引出一个问题,它的这个向上查找的序列究竟是怎样一种算法呢?

这里使用的是一种C3算法用来计算Python的类的多继承的规则。

它计算出来的是一个MRO的有序列表,它是在类创建的时候就被创建出来的。

它的通用公式是:

 mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2),  [ Base1, Base2] )
(其中Child继承自Base1, Base2)

这个公式其实是很简单的,下面稍后举一个详细的例子看一遍就很容易理解了。

这里介绍它的两个概念,表头:列表的第一个元素,表尾:列表的除了首个元素的其他元素。

Merge操作流程图

接下来做一个具体的实例:

先给出一个具体的继承关系:

C3

接下来是自己推算的计算步骤:

mro(A1) = mro(A1(O))
= [A1] + merge(mro[O])
= [A1] + merge([O])
= [A1, O]

mro(A2) = mro(A2(O))
= [A2] + merge(mro[O])
= [A2] + merge([O])
= [A2, O]

mro(A3) = mro(A3(O))
= [A3] + merge(mro[O])
= [A3] + merge([O])
= [A3, O]

======================================================================================
mro(B1) = mro(B1(A1, A2))
= [B1] + merge(mro(A1) + mro(A2) + [A1, A2])
= [B1] + merge([A1, O] + [A2, O] + [A1, A2])
= [B1, A1] + merge([O] + [A2, O] + [A2])
= [B1, A1, A2] + merge([O] + [O])
= [B1, A1, A2, O]

mro(B2) = mro(B2(A2, A3))
= [B2] + merge(mro(A2) + mro(A3) + [A2, A3])
= [B2] + merge([A2, O] + [A3, O] + [A2, A3])
= [B2, A2] + merge([O] + [A3, O] + [A3])
= [B2, A2, A3] + merge([O] + [O])
= [B2, A2, A3, O]

mro(B3) = mro(B3(A3))
= [B3] + merge(mro(A3))
= [B3] + merge([A3, O])
= [B3, A3, O]

======================================================================================
mro(C1) = mro(C1(B1))
= [C1] + merge(mro(B1))
= [C1] + merge([B1, A1, A2, O])
= [C1, B1, A1, A2, O]

mro(C2) = mro(C2(B1, B2))
= [C2] + merge(mro(B1) + mro(B2) + [B1, B2])
= [C2] + merge([B1, A1, A2, O] + [B2, A2, A3, O] + [B1, B2])
= [C2, B1] + merge([A1, A2, O] + [B2, A2, A3, O] + [B2])
= [C2, B1, A1] + merge([A2, O] + [B2, A2, A3, O] + [B2])
= [C2, B1, A1, B2] + merge([A2, O] + [A3, O])
= [C2, B1, A1, B2, A2] + merge([O] + [A3, O])
= [C2, B1, A1, B2, A2, A3, O]

mro(C3) = mro(C3(B2, B3))
= [C3] + merge(mro(B2) + mro[B3] + [B2, B3])
= [C3] + merge([B2, A2, A3, O] + [B3, A3, O] + [B2, B3])
= [C3, B2] + merge([A2, A3, O] + [B3, A3, O] + [B3])
= [C3, B2, A2] + merge([A3, O] + [B3, A3, O] + [B3])
= [C3, B2, A2, B3] + merge([A3, O] + [A3, O])
= [C3, B2, A2, B3, A3, O]

======================================================================================
mro(D) = mro(D(C1, C2, C3))
= [D] + merge(mro(C1) + mro(C2) + mro(C3) + [C1, C2, C3])
= [D] + merge([C1, B1, A1, A2, O] + [C2, B1, A1, B2, A2, A3, O] + [C3, B2, A2, B3, A3, O] + [C1, C2, C3])
= [D, C1] + merge([B1, A1, A2, O] + [C2, B1, A1, B2, A2, A3, O] + [C3, B2, A2, B3, A3, O] + [C2, C3])
= [D, C1, C2] + merge([B1, A1, A2, O] + [B1, A1, B2, A2, A3, O] + [C3, B2, A2, B3, A3, O] + [C3])
= [D, C1, C2, B1] + merge([A1, A2, O] + [A1, B2, A2, A3, O] + [C3, B2, A2, B3, A3, O] + [C3])
= [D, C1, C2, B1, A1] + merge([A2, O] + [B2, A2, A3, O] + [C3, B2, A2, B3, A3, O] + [C3])
= [D, C1, C2, B1, A1, C3] + merge([A2, O] + [B2, A2, A3, O] + [B2, A2, B3, A3, O])
= [D, C1, C2, B1, A1, C3, B2] + merge([A2, O] + [A2, A3, O] + [A2, B3, A3, O])
= [D, C1, C2, B1, A1, C3, B2, A2] + merge([O] + [A3, O] + [B3, A3, O])
= [D, C1, C2, B1, A1, C3, B2, A2, B3] + merge([O] + [A3, O] + [A3, O])
= [D, C1, C2, B1, A1, C3, B2, A2, B3, A3] + merge([O] + [O] + [O])
= [D, C1, C2, B1, A1, C3, B2, A2, B3, A3, O]

仔细看完这几个类的推算步骤,差不多可以理解这个C3算法的步骤了。

接下来给出代码验证:

class A1:
   pass


class A2:
   pass


class A3:
   pass


class B1(A1, A2):
   pass


class B2(A2, A3):
   pass


class B3(A3):
   pass


class C(B1, B2, B3):
   pass


class C1(B1):
   pass


class C2(B1, B2):
   pass


class C3(B2, B3):
   pass


class D(C1, C2, C3):
   pass


for i in D.mro():
   print(i)

直接查看结果:

<class '__main__.D'>
<class '__main__.C1'>
<class '__main__.C2'>
<class '__main__.B1'>
<class '__main__.A1'>
<class '__main__.C3'>
<class '__main__.B2'>
<class '__main__.A2'>
<class '__main__.B3'>
<class '__main__.A3'>
<class 'object'>

由此可见和我们推算的结果一致。

其他类的代码验证结果这里就不再放了,D类的结果得到验证的情况下,其他类的推算结果就一定是正确的。

原文地址:https://www.cnblogs.com/hexiaoqi/p/13155866.html