为什么Python的C3 MRO依赖于一个共同的基类?

时间:2016-09-14 10:37:11

标签: python multiple-inheritance method-resolution-order

当我读到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会发生变化(即使整个层次结构与该链接相同),并且您开始调用更深层次的祖先方法而不是那个班。

1 个答案:

答案 0 :(得分:2)

Python 3中的所有类都有一个公共基类object。您可以从class定义中省略该类,但除非您已经间接继承自object,否则它将存在。 (在Python 2中,您必须明确地继承object甚至使用super(),因为这是一种新式的类功能。)

您将B的基类从X更改为object,但X 继承自object。 MRO改为考虑到这一点。 C3规则的相同简化(孩子来到父母之前,子类的顺序得到尊重)仍然适用于此。 Bobject之前,X也是如此,AB仍以相同的顺序列出。但是,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)