Python多重继承和super()

时间:2015-11-23 09:35:10

标签: python inheritance constructor multiple-inheritance

我试图了解多重继承(即C3 algorithm for method resolution order)在Python中是如何工作的。下面使用经典diamond dependency的玩具示例给出了违背我直觉的结果。

特别是,我注意到以下内容:

  1. 按原样投放(即,AAA都有superBase次来电,输出为:<B> <A> <AA> <Base> </Base> </AA> </A> </B>
  2. 当只有标记为(1)的行被注释掉(即,Base中没有调用A构造函数)时,输出为<B> <A> </A> </B>
  3. 当只有标记为(2)的行被注释掉(即,Base中没有调用AA构造函数)时,输出为<B> <A> <AA> </AA> </A> </B>
  4. 如果标记为(1)(2)的两行都已注释掉,则输出为<B> <A> </A> </B>
  5. 我的问题是:

    • 在案例1中,似乎在显式调用A构造函数之前,Base的构造函数中的执行被中断,跳转到(“recurses into”)AA构造函数(好像AA派生自A),然后下降到Base,然后退出。这是怎么回事? (我理解MRO B->A->AA->Base来自C3要求,即在父类之前调用​​子类。)
    • 在案例2中,为什么AA的构造函数从未被调用,尽管在案例3中它被调用了?
    • 在案例2和3中,尽管在Base(案例2)/ AA(案例3)的构造函数中进行了显式调用,为什么未调用A构造函数? (在示例1中,它正如我所期望的那样被调用。)

    以下是班级的MRO:

    • 班级B(<class '__main__.B'>, <class '__main__.A'>, <class '__main__.AA'>, <class '__main__.Base'>, <type 'object'>)
    • 班级A(<class '__main__.A'>, <class '__main__.Base'>, <type 'object'>)
    • 班级AA(<class '__main__.AA'>, <class '__main__.Base'>, <type 'object'>)
    • 班级Base(<class '__main__.Base'>, <type 'object'>)

    代码:

    #!/usr/bin/env python
    # Using Python 2.7
    
    class Base(object):
        def __init__(self):
            print '<Base>',
            super(Base, self).__init__()
            print '</Base>',
    
    class A(Base):
        def __init__(self):
            print '<A>',
            super(A, self).__init__()             # (1)
            print '</A>',
    
    class AA(Base):
        def __init__(self):
            print '<AA>',
            super(AA, self).__init__()            # (2)
            print '</AA>',
    
    class B(A, AA):
        def __init__(self):
            print '<B>',
            super(B, self).__init__()
            print '</B>',
    
    if __name__ == '__main__':
        obj = B()
    

2 个答案:

答案 0 :(得分:0)

来自您链接的维基百科文章:

  

Python使用C3线性化算法创建类列表。该算法强制执行两个约束:子节点在它们的父节点之前,如果一个类从多个类继承,它们将按照基类元组中指定的顺序保存(但是在这种情况下,继承图形中高的某些类可能位于较低的类之前图[8])。因此,方法分辨率顺序为:D,B,C,A

因此在这种情况下(即,在B的继承结构中),A的超级是AA。

答案 1 :(得分:0)

MRO是var backgroundcolor = ["red", "green", "white"]; $('option').click(function() { $(this).parent().css("background-color", backgroundcolor[$(this).val()]); });BAAA。这意味着当Basesuper(A, self)对象时self的值是B类的代理。如果您构建了AA个对象,则相同的A调用将返回super类的代理。

令你困惑的所有行为都直接源于此。

在A对象中,Base来电将调用super(A,self).__init__(),但B对象中的同一来电将调用Base.__init__(self)

修改以在评论中添加问题的答案:

不,你找不到super解析的类,原因很简单,因为不同的属性可以解析为不同的类。

例如,在代码中为AA.__init__(self)提供方法class AA。现在:

foo

b = B() super(B,b).__init__() # calls A.__init__ super(B,b).foo() # calls AA.foo 函数不仅找到MRO链中的下一个类,它还会找到具有所需属性的下一个类。这就是为什么它必须返回一个代理对象而不是只返回一个类。

相关问题