Python多重继承和super()
我试图理解Python中多重继承(即)是如何工作的。下面的经典玩具示例给出的结果与我的直觉相反 我特别注意到以下几点:Python多重继承和super(),python,inheritance,constructor,multiple-inheritance,Python,Inheritance,Constructor,Multiple Inheritance,我试图理解Python中多重继承(即)是如何工作的。下面的经典玩具示例给出的结果与我的直觉相反 我特别注意到以下几点: 当按原样运行时(即A和AA都有super调用Base,则输出为: 当仅注释掉标记为(1)的行时(即在A中不调用Base构造函数),则输出为 当仅注释掉标记为(2)的行时(即,AA中没有调用Base构造函数),则输出为 当标记为(1)和(2)的两行都被注释掉时,输出为 我的问题是: 在案例1中,在显式调用Base构造函数之前,A的构造函数中的执行似乎被中断,跳转到AA构造函数(
A
和AA
都有super
调用Base
,则输出为:
(1)
的行时(即在A
中不调用Base
构造函数),则输出为
(2)
的行时(即,AA
中没有调用Base
构造函数),则输出为
(1)
和(2)
的两行都被注释掉时,输出为
- 在案例1中,在显式调用
构造函数之前,Base
的构造函数中的执行似乎被中断,跳转到A
构造函数(好像AA
将派生自AA
),然后下降到A
,然后返回。会发生这种情况吗?(我理解MROBase
来自C3要求在父类之前调用子类。)B->A->AA->Base
- 在案例2中,为什么从未调用
的构造函数,尽管在案例3中调用了它AA
- 在案例2和案例3中,尽管在
(案例2)/AA
(案例3)的构造函数中进行了显式调用,但为什么没有调用A
构造函数(在示例1中,它是按我的预期进行调用的)Base
- 类
:B
(,)
- 类
:A
(,)
- 类别
:AA
(,)
- 类
:Base
(,)
!/usr/bin/env python
#使用Python2.7
类基(对象):
定义初始化(自):
打印“”,
超级(基本,自我)。\uuuuu初始
打印“”,
A类(基本类):
定义初始化(自):
打印“”,
超级(A,自我)。(1)
打印“”,
AA级(基本):
定义初始化(自):
打印“”,
超级(AA,self)。uuuu初始(2)
打印“”,
B类(A、AA):
定义初始化(自):
打印“”,
super(B,self)。\uuuuu init\uuuuuuu()
打印“”,
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
obj=B()
来自您链接的维基百科文章:
Python使用C3线性化算法创建一个类列表。该算法强制执行两个约束:子类在其父类之前,如果一个类从多个类继承,则它们将保持在基类元组中指定的顺序(然而,在这种情况下,继承图中较高的一些类可能位于图[8]中较低的类之前。)因此,方法解析顺序为:D,B,C,A
因此在这种情况下(即,在B的继承结构中),A的super是AA。MRO是
B
,A
,AA
,Base
。这意味着super(A,self)的值
当self
是B
时,对象是AA
类的代理。如果构建了a
对象,则相同的super
调用将返回Base
类的代理
所有让你困惑的行为都直接源于此
在A对象中,super(A,self).\uuu init\uuuuuuuuuuuuuuuuuuuuuuuuuu()调用将调用Base.\uuuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuself)
,但
编辑以在评论中添加问题的答案:
不,您找不到super解析的类,原因很简单,不同的属性可以解析为不同的类
例如,在您的代码中,给出class AA
方法foo
。现在:
b = B()
super(B,b).__init__() # calls A.__init__
super(B,b).foo() # calls AA.foo
super
函数不只是查找MRO链中的下一个类,它还查找具有所需属性的下一个类。这就是为什么它必须返回代理对象,而不仅仅是返回类。您不应该将super
视为对下一个“up”的函数调用相反,当正确使用时,super
将确保以该顺序调用MRO中的所有函数。但为了实现该top,需要在该链的每个段中进行super调用
因此,如果您在A
或AA
中删除超级调用,则链将中断。根据您删除的内容,链将在A
或AA
处中断:
- 不间断(完整MRO):
B
,A
,AA
,Base
- 案例1(在
A
中没有超级调用):B
,A
- 案例2(在
AA
中没有超级调用);B
,A
,AA
因此,您应该记住始终在所有涉及的类型中使用super,以使其正常工作
如果你想了解更多关于super
,你应该去今年的PyCon看看。它有很好的解释,还有一些简单易懂的例子(涉及真实的人!)
引用他的话(抄写并强调我的话):
Python中的super
最大的问题是什么?这不是它的设计。我认为它的设计完美无缺,很漂亮,Guido在这方面做得非常出色
问题是名称,它不应该被称为“super”。为什么不呢?答案是,如果你用任何其他语言学习super,它与Python都不一样
[…]它在其他语言中起什么作用?我
b = B()
super(B,b).__init__() # calls A.__init__
super(B,b).foo() # calls AA.foo