Python多重继承和super()

Pow*_*ool 5 python inheritance constructor multiple-inheritance

我试图理解多重继承(即方法解析顺序C3算法)如何在Python中工作.以下经典钻石依赖的玩具示例给出了违背我直觉的结果.

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

  1. 当运行原样(即两者AAAsuper将呼叫Base,则输出是:<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>.

我的问题是:

  • 在情况1中,似乎执行A在显式调用构造函数之前在构造函数中被中断Base,跳转到("recurses into")AA构造函数(就好像AA将从中派生A),然后进入Base,然后退出.这是怎么回事?(我理解MRO B->A->AA->Base来自C3要求,即在父类之前调用​​子类.)
  • 在案例2中,为什么AA永远不会调用构造函数,尽管在案例3中它被调用?
  • 在情况2和3中,为什么Base没有调用构造函数,尽管在AA(情况2)/ A(情况3)的构造函数中有显式调用?(在例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()
Run Code Online (Sandbox Code Playgroud)

pok*_*oke 2

您不应该将 \xe2\x80\x99t 视为super对继承链中下一个 \xe2\x80\x9cup\xe2\x80\x9d 的函数调用。相反,如果使用得当,super将确保 MRO 中的所有函数都按该顺序调用。但为了实现这一点,该链的每个部分都需要进行超级调用。

\n\n

A因此,如果您删除其中任一中的超级调用,AA则链会中断。根据您删除的内容,链会在A或处中断AA

\n\n
    \n
  • 不间断(完整 MRO):B, A, AA,Base
  • \n
  • 情况1(没有超级呼入A):B,A
  • \n
  • 情况2(没有超级呼入AA);B, A,AA
  • \n
\n\n

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

\n\n

如果您想了解有关 的更多信息super,您应该查看今年\xe2\x80\x99s PyCon 上的 Raymond Hettinger\xe2\x80\x99s 演讲 \xe2\x80\x9cSuper 被认为是超级!\xe2\x80\x9d 。它解释得很好,并且还有一些易于理解的示例(涉及真人!)。

\n\n

引用他那次演讲的内容(我的转录和强调):

\n\n
\n

superPython 中最大的问题是什么\xe2\x80\x99 ?它\xe2\x80\x99s不是它的设计。我认为它的设计是完美的,它很漂亮,Guido 做得非常出色。

\n\n

问题是名称,它不应该被称为\xe2\x80\x9csuper\xe2\x80\x9d。为什么不?答案是,如果你用任何其他语言学习 super,它的作用与 Python 的作用是不同的。

\n\n

[\xe2\x80\xa6] 它在其他语言中的作用是什么?在其他语言中,它会打电话给你的父母。[\xe2\x80\xa6] 继承,无论什么时候打电话super都是给父母打电话。但 Python\xe2\x80\x99s 做了一些不同的事情。它确实呼唤父母,但不是你的父母。当你打电话时super,谁的父母会接到电话?它不是你的祖先,它\xe2\x80\x99是你的孩子\xe2\x80\x99的祖先。

\n
\n