2015-10-19 66 views
0

我对python多继承有点困惑。python多继承超级函数

例如,如果你有:

class A(object): 
def __init__(self): 
    print "init A" 
    super(A, self).__init__() 

class B(A): 
    def __init__(self): 
     print "init B" 
     super(B, self).__init__() 

class C(A): 
    def __init__(self): 
     print "init C" 
     super(C, self).__init__() 

class D(C, B): 
    def __init__(self): 
     print "init D" 
     super(D, self).__init__() 

if __name__ == '__main__': 
    D() 

的方法解析顺序(MRO)将D-C-B-A。

为什么顺序不是d-C-A-B-A?

+0

因为你不能在mro中有重复的东西... – Bakuriu

+0

的确,Python的继承系统的整个设计是使钻石继承方案像你所展示的那样。由于重复路径到达最终基类,它们倾向于在其他语言(如C++)中做坏事。 – Blckknght

回答

1

你只实例化一个对象。 Python允许每个祖先的__init__在MRO中只执行一次。因此,我们没有得到这两个A-> C和A-> B关系,执行A.__init__

由于只有这么多解释,你可能会认为我们会得到DCAB ...但由于B也需要A.__init__,则在确定执行顺序之前,MRO有足够的耐心解决整个图形。

2

Python文档:

有了新的样式类,动态排序是必要的,因为多重继承展览的一个或多个菱形关系(父类,其中至少一个所有病例可以通过多条路径访问来自最底层的课程)。例如,所有新样式的类都从对象继承,所以任何多继承的情况都会提供多条路径来达到对象。 为了保持基类被访问一次以上,动态算法线性化的方式搜索顺序,保留在每类中指定的左到右的顺序,即要求每个家长只有一次,那就是单调(这意味着一个类可以在不影响其父母的优先顺序的情况下进行子类化)。综合起来,这些属性使设计具有多继承性的可靠和可扩展的类成为可能。有关更多详细信息,请参见https://www.python.org/download/releases/2.3/mro/

1

粗略地说,MRO是通过将所有基底先深度优先,从左到右,然后删除任何重复项,然后删除最后一项来给出的。

的算法是这样的,对于任何的基类,基类的MRO订单将始终是相同的(如果这是不可能的,我相信你会得到一个错误)。

如果重复未删除,则顺序实际上是d-C-A-对象-B-A-对象。由于多种原因,这是令人困惑的。首先,如果方法调用super,就像你的情况一样,那么同样的方法可以被调用两次。其次,B的实现期望在A之前并且在方法解析顺序中反对是合理的。如果它覆盖了A的属性,则不会预期这个覆盖将被颠倒。

1

究其原因,是MRO d-C-B-A的是,它是d-C-A-B-A(或d-C-A-B)将具有奇怪的效果。在这个特殊的例子中,A类的构造函数没有参数明确是否super()电话,只有在钻石继承树事项。如果它没有执行super调用,则不会从A构造函数调用B构造函数。如果构造函数有参数,那么A的构造函数会卡在岩石和坚硬的地方之间。如果它不叫super那么它不适用于钻石继承。如果它确实叫super那么,因为object.__init__没有参数,所以构造函数会失败,如果它没有用于钻石继承模式。