Python 多重继承和 super()

Python multiple inheritance and super()

我试图了解多重继承(即下面的 C3 algorithm for method resolution order) works in Python. The toy example with the classical diamond dependency 给我的结果与我的直觉相反。

我特别注意到以下几点:

  1. 当 运行 按原样(即 AAA 都有 super 调用 Base 时,输出为:<B> <A> <AA> <Base> </Base> </AA> </A> </B>.
  2. 当只有标记为(1)的行被注释掉时(即没有调用A中的Base构造函数),则输出为<B> <A> </A> </B>
  3. 当只有标记为(2)的行被注释掉时(即没有调用AA中的Base构造函数),则输出为<B> <A> <AA> </AA> </A> </B>
  4. 当标记为 (1)(2) 的两行都被注释掉时,输出为 <B> <A> </A> </B>.

我的问题是:

这是 类 的 MRO:

代码:

#!/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()

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

Python creates a list of classes using the C3 linearization algorithm. That algorithm enforces two constraints: children precede their parents and if a class inherits from multiple classes, they are kept in the order specified in the tuple of base classes (however in this case, some classes high in the inheritance graph may precede classes lower in the graph[8]). Thus, the method resolution order is: D, B, C, A

所以在这种情况下(即在B的继承结构中),A的上级是AA。

MRO 为 BAAABase。这意味着当 selfB 对象时 super(A, self) 的值是 AA class 的代理。如果您构建了一个 A 对象,则相同的 super 调用将 return 成为 Base class.

的代理

所有让您感到困惑的行为都直接源于此。

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

编辑以在您的评论中添加问题的答案:

不,您找不到由 super 解析的 class,原因很简单,不同的属性可以解析为不同的 classes。

例如,在您的代码中给 class AA 一个方法 foo。现在:

b = B()
super(B,b).__init__() # calls A.__init__
super(B,b).foo() # calls AA.foo

super 函数不仅在 MRO 链中找到下一个 class,它还会找到具有所需属性的下一个 class。这就是为什么它必须 return 一个代理对象而不仅仅是 return 一个 class.

您不应将 super 视为对继承链中下一个“上层”的函数调用。相反,如果使用得当,super 将确保 MRO 中的所有函数都按该顺序调用。但为了实现这一目标,需要在该链的每个部分进行超级调用。

因此,如果您在 AAA 中删除 super 调用,则链会中断。根据您删除的内容,链会在 AAA:

处中断
  • 不间断(完整 MRO):BAAABase
  • 情况 1(A 中没有超级调用):BA
  • 情况 2(AA 中没有 super 调用); BAAA

因此,您应该牢记在所有涉及的类型中始终始终如一地使用 super 以使其正常运行。

如果您想了解有关 super 的更多信息,您应该在今年的 PyCon 上查看 Raymond Hettinger’s talk “Super considered super!”。它解释得很好,还有一些简单易懂的例子(涉及真人!)。

引用他在那次演讲中的话(转录和强调我的):

What’s our biggest problem with super in Python? It’s not its design. Its design I think is flawless, it’s beautiful, Guido did an extraordinary job with it.

The problem is the name, it shouldn’t have been called “super”. Why not? The answer is, if if you learn super in any other language, it doesn’t do the same as Python.

[…] What does it do in other languages? In other languages, it calls your parents. […] Inheritance, whenever you call super is about calling your parents. But Python’s does something different. It does call parents, but not your parents. When you call super, whose parents get called? It is not your ancestors, it’s your children’s ancestors.