当我读到Python的C3方法解析顺序时,我经常听到它缩减为"孩子们来到父母之前,并且子类的顺序得到尊重"。然而,如果所有子类都继承自相同的祖先,那么这似乎只是成立。
E.g。
class X():
def FOO(self):
return 11
class A(X):
def doIt(self):
return super().FOO()
def FOO(self):
return 42
class B(X):
def doIt(self):
return super().FOO()
def FOO(self):
return 52
class KID(A,B):
pass
这里KID的MRO是: KID,A,B,X
但是,如果我将B改为:
class B(object):
KID的MRO成为: KID,A,X,B
在我们搜索完所有KID的父母之前,我们似乎正在搜索超级班。
所以它现在看起来有点不那么直观了,而且#34;孩子优先,广度优先"首先是孩子,如果共同的祖先是第一个深度,那么首先是广度,#34;。
如果一个类停止使用共同的祖先,MRO会发生变化(即使整个层次结构与该链接相同),并且您开始调用更深层次的祖先方法而不是那个班。
答案 0 :(得分:2)
Python 3中的所有类都有一个公共基类object
。您可以从class
定义中省略该类,但除非您已经间接继承自object
,否则它将存在。 (在Python 2中,您必须明确地继承object
甚至使用super()
,因为这是一种新式的类功能。)
您将B
的基类从X
更改为object
,但X
也继承自object
。 MRO改为考虑到这一点。 C3规则的相同简化(孩子来到父母之前,子类的顺序得到尊重)仍然适用于此。 B
在object
之前,X
也是如此,A
和B
仍以相同的顺序列出。但是,X
应该在B
之前,因为它们都来自object
而子类A(X)
来自B
中的KID
。
请注意,没有地方说C3首先是广度。如果有的话,它首先是深度。有关算法及其如何应用于Python的深入描述,请参阅The Python 2.3 Method Resolution Order,但任何类的线性化都是合并基类的线性化和基类本身的结果:
L[KID] = KID + merge(L[A], L[B], (A, B))
其中L[..]
是该类(他们的MRO)的C3线性化。
因此A
的线性化在B
合并之前出现,使C3在深度而不是广度上看待层次结构。合并从最左边的列表开始,并采用任何未出现在其他列表的尾部的元素(除了第一个元素之外的所有内容),然后接下一个等等。
在您的第一个示例中,L[A]
和L[B]
几乎相同(它们都以(X, object)
作为其MRO结尾,只有第一个元素不同),因此合并很简单;您合并(A, X, object)
和(B, X, object)
,合并这些内容只会在第一个列表中提供A
,然后在整个第二个列表中提供(KID, A, B, X, object)
,前提KID
}:
L[KID] = KID + merge((A, X, object), (B, X, object), (A, B))
# ^ ^^^^^^
# \ & \ both removed as they appear in the next list
= KID + (A,) + (B, X, object)
= (KID, A, B, X, object)
在您的第二个示例中,L[A]
未更改,但L[B]
现在为(B, object)
(正在删除X
),因此合并时更喜欢X
1}}在B
之前,(A, X, object)
在合并时首先出现,X
未出现在第二个列表中。因此
L[KID] = KID + merge((A, X, object), (B, object), (A, B))
# ^^^^^^
# \removed as it appears in the next list
= KID + (A, X) + (B, object)
= (KID, A, X, B, object)