是的,如介绍新算法以计算方法分辨率顺序(即C3 线性化)的文档中所述,可以保证。
不使用此算法的mro
实现并不真正符合 python 语言(版本 2.3+)。AFAIK 所有当前的实现都使用 C3 线性化。
C3 线性化满足局部优先排序和单调性属性。本地优先顺序意味着一个类C(B1, ..., Bn)
将按照它们在继承列表中列出的顺序在其mro
基类中具有。Bi
单调性可能用一个例子更好地解释:
>>> class A(object): pass
>>> class B(object): pass
>>> class C(object): pass
>>> class D(object): pass
>>> class E(object): pass
>>> class K1(A,B,C): pass
>>> class K2(D,B,E): pass
>>> class K3(D,A): pass
>>> class Z(K1,K2,K3): pass
python2.2的旧mro(不是单调的),这些是上述类的线性化:
L[A] = A O
L[B] = B O
L[C] = C O
L[D] = D O
L[E] = E O
L[K1]= K1 A B C O
L[K2]= K2 D B E O
L[K3]= K3 D A O
L[Z] = Z K1 K3 A K2 D B C E O
# in current versions of python (2.3+):
# L[Z] = Z K1 K2 K3 D A B C E O
在这里你可以看到,在 的线性化中Z
,类A
出现在 之前D
,而在K3
它的线性化中,类出现在之后 D
。单调性是线性化的属性,因此在继承时没有这种交换。如果一个类在类的父X
类Y
的所有线性化中都在类之前,那么它Y
在最终的线性化中也将在类之前。
现在,如果我们考虑一个类C(B1, ..., Bn)
。通过局部优先顺序,B1, ..., Bn
将在 的线性化中按该顺序找到类C
。通过单调性,我们无法在自身Bi
之前找到 s 的子类。Bi
由此得出 的线性化C
,如果存在的话,必须从C
和开始B1
。
请注意,在某些情况下,您无法计算线性化,python 会抱怨,例如:
>>> class A(object):pass
...
>>> class B(object, A): pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Cannot create a consistent method resolution
order (MRO) for bases object, A
但是,如果您交换类,则可以线性化层次结构:
>>> class B(A, object): pass
...
>>> B.mro()
[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
如果父类没有共同的基础(object
显然其他),那么很明显 的线性化C(B1, ..., Bn)
将从B1
(除了object
)的线性化开始,然后将遵循B2
etc 的线性化,并以 的线性化结束Bn
:
>>> class A(object): pass
...
>>> class B(object): pass
...
>>> class A1(A): pass
...
>>> class A2(A1): pass
...
>>> class B1(B): pass
...
>>> class C(object): pass
...
>>> class C1(C): pass
...
>>> class C2(C1):pass
...
>>> class C3(C2): pass
...
>>> class D(A2, B1, C3): pass
...
>>> D.mro()
[<class '__main__.D'>, <class '__main__.A2'>, <class '__main__.A1'>, <class '__main__.A'>, <class '__main__.B1'>, <class '__main__.B'>, <class '__main__.C3'>, <class '__main__.C2'>, <class '__main__.C1'>, <class '__main__.C'>, <class 'object'>]
当您在 s 之间有一些公共子类时,事情开始变得很奇怪,Bi
在这种情况下,python 会找到您期望的不违反本地优先顺序和单调性的顺序,否则会引发错误。