C3算法
Python 至少用过三种不同的 MRO 算法:经典类所用的算法,Python 2.2 中的新式类所用算法,以及 Python 2.3 中的新式类所用的算法(也称 C3算法),而在 Python 3 中,只留下了最后一种算法。
C3是如何构建一个类的线性化(优先级)。这个列表可用于属性查找。
MRO
MRO的变化是用于解决创建公共基本类型(object)所引入的问题。在C3线性化方法之前,如果一个类有两个祖先(图3-1),那么对于不使用多重继承模型的简单情况来说,方法解析顺序的计算和跟踪都非常简单。
示例图
>>> class Base1:
... pass
...
>>> class Base2:
... def method(self):
... print('Base2')
...
>>>
>>> class Myclass(Base1, Base2):
... pass
...
>>> Myclass.__mro__
(<class 'Myclass'>, <class 'Base1'>, <class 'Base2'>, <class 'object'>)
>>> Myclass().method()
Base2
# 当调用MyClass().method()时,解释器会首先在MyClass中查找这一方法,然后在Base1中查找,最终在Base2中找到
# 经典类中的 MRO 算法非常简单:深度优先,从左至右,返回找到的第一个结果
Base1和Base2基类引入某个类
双祖先类再引入某个CommonBase类(Base1和Base2都从其继承,图3-2),将变得更加复杂。其结果,根据“从左到右、深度优先”规则的简单解析顺序,在查找Base2类之前就通过Base1类回到顶部。这一算法会导致反直觉的结果。在某些情况下,执行的方法可能并不是在继承树中最为接近的那个方法。
Python 2中继承
>>> class CommonBase:
... def method(self):
... print('CommonBase')
...
>>>
>>> class Base1(CommonBase):
... pass
...
>>>
>>> class Base2(CommonBase):
... def method(self):
... print('Base2')
...
>>>
>>> class Myclass(Base1, Base2):
... pass
...
>>>
>>> Myclass().method()
CommonBase
# Base2.method()没有被调用,虽然在类层次结构中 Base2 比 CommonBase 要更近一些。
# 这样的继承情景是极其少见的,因此更多的是一个理论问题而不是实践问题。
Python 3中继承
>>> class CommonBase:
... def method(self):
... print('CommonBase')
...
>>>
>>> class Base1(CommonBase):
... pass
...
>>>
>>> class Base2(CommonBase):
... def method(self):
... print('Base2')
...
>>>
>>> class Myclass(Base1, Base2):
... pass
...
>>>
>>> Myclass().method()
Base2
# 现在Python3中所有类具有相同的共同祖先。由于使用现有的MRO使其正常工作要花费太多的精力,所以提供一个新的MRO是更为简单、快捷的解决方案。
# 这种用法表明,C3序列化会挑选最接近的祖先的方法。