我试图了解多重继承(即C3 algorithm for method resolution order)在Python中是如何工作的。下面使用经典diamond dependency的玩具示例给出了违背我直觉的结果。
特别是,我注意到以下内容:
A
和AA
都有super
次Base
次来电,输出为:<B> <A> <AA> <Base> </Base> </AA> </A> </B>
。(1)
的行被注释掉(即,Base
中没有调用A
构造函数)时,输出为<B> <A> </A> </B>
。(2)
的行被注释掉(即,Base
中没有调用AA
构造函数)时,输出为<B> <A> <AA> </AA> </A> </B>
。(1)
和(2)
的两行都已注释掉,则输出为<B> <A> </A> </B>
。我的问题是:
A
构造函数之前,Base
的构造函数中的执行被中断,跳转到(“recurses into”)AA
构造函数(好像AA
派生自A
),然后下降到Base
,然后退出。这是怎么回事? (我理解MRO B->A->AA->Base
来自C3要求,即在父类之前调用子类。)AA
的构造函数从未被调用,尽管在案例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()
答案 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()]);
});
,B
,A
,AA
。这意味着当Base
是super(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链中的下一个类,它还会找到具有所需属性的下一个类。这就是为什么它必须返回一个代理对象而不是只返回一个类。