2010-09-03 85 views
4

钻石型继承非常简单的例子:的Python 3.1:C3方法解析顺序

class Root: 
    def f(self): 
     print('Root') 

class A(Root): pass 

class B(Root): 
    def f(self): 
     print('B') 

class AB(A, B): pass 

AB().f() 

根据Python 3.1.2 documentation

在大多数情况下,在最简单的 情况下,你能想到的搜索 属性从父类 继承的属性为深度优先,从左到右, 不在相同类中搜索两次 其中中存在重叠层次结构。

因此,我希望我的例子按照AB - > A - > Root - > B的顺序来解决,但事实并非如此。使用ActiveState Python 3.1.2,输出是'B'而不是'Root'。

我错过了什么?

另外,我注意到ActiveState Python 2.6用相同的代码打印'Root'。决议规则是否在2.6和3.1之间变化?

回答

9

Python 2.6打印根因为Root是一个旧式的类。如果Root继承自object(使其成为新风格的类),则应打印B

旧式课程并未使用C3 MRO,而是旧式的有缺陷的MRO,这正是您引用的文本所描述的内容。


B在Root之前出现的原因是因为B也从Root继承。

AB的继承图是:

AB - A - Root -- object 
    \ /
     B 

所以:

mro(object) = [object] 
mro(Root) = [Root] + mro(object) # mro of single-inherited class is simple... 
      = [Root, object] 
mro(A)  = [A, Root, object] 
mro(B)  = [B, Root, object] 

在多重继承的情况下,MRO是通过采取超类的活性氧代谢的元素从左至右计算,这并不出现在中间。在例子中更好地解释:

mro(AB) = [AB] + merge(mro(A), mro(B)) 
     = [AB] + merge([A, Root, object], [B, Root, object]) 
     = [AB] + [A] + merge([Root, object], [B, Root, object]) 
      # A appears at head, pop it. 
     = [AB] + [A] + [B] + merge([Root, object], [Root, object]) 
      # cannot pop Root because Root is not at head of [B, Root, object] 
      # pop B instead. 
     = [AB] + [A] + [B] + [Root] + merge([object], [object]) 
      # now we can pop Root because it only appears at the head position 
     = [AB] + [A] + [B] + [Root] + [object] 
     = [AB, A, B, Root, object] 

更多详细信息请参见http://www.python.org/download/releases/2.3/mro/

+0

因此,文档解释“搜索从父类继承的属性为深度优先,从左到右,而不是在同一类中存在层次结构重叠的地方进行两次搜索”并不是很好,我应该忽略它吗? – max 2010-09-03 17:23:26

+0

@max:“在最简单的情况下”是好的。你的例子并不是最简单的。 – kennytm 2010-09-03 17:36:23