Python 的 super() 如何处理多重继承?

新手上路,请多包涵

super() 如何处理多重继承?例如,给定:

 class First(object):
    def __init__(self):
        print "first"

class Second(object):
    def __init__(self):
        print "second"

class Third(First, Second):
    def __init__(self):
        super(Third, self).__init__()
        print "that's it"

Third 的哪个父方法 super().__init__ 指的是什么?我可以选择运行哪些吗?

我知道它与方法解析顺序 ( MRO ) 有关。

原文由 Callisto 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 312
2 个回答

Guido 本人在他的博客文章 Method Resolution Order (包括之前的两次尝试)中详细介绍了这一点。

在您的示例中, Third() 将调用 First.__init__ 。 Python 查找类的父类中的每个属性,因为它们是从左到右列出的。在这种情况下,我们正在寻找 __init__ 。所以,如果你定义

class Third(First, Second):
    ...

Python 将首先查看 First ,如果 First 没有属性,那么它将查看 Second

当继承开始跨越路径时,这种情况变得更加复杂(例如,如果 First 继承自 Second )。阅读上面的链接了解更多详细信息,但是,简而言之,Python 将尝试维护每个类在继承列表中出现的顺序,从子类本身开始。

因此,例如,如果您有:

 class First(object):
    def __init__(self):
        print "first"

class Second(First):
    def __init__(self):
        print "second"

class Third(First):
    def __init__(self):
        print "third"

class Fourth(Second, Third):
    def __init__(self):
        super(Fourth, self).__init__()
        print "that's it"

MRO 将是 [Fourth, Second, Third, First].

顺便说一句:如果 Python 找不到一致的方法解析顺序,它会引发异常,而不是退回到可能让用户感到惊讶的行为。

模棱两可的 MRO 示例:

 class First(object):
    def __init__(self):
        print "first"

class Second(First):
    def __init__(self):
        print "second"

class Third(First, Second):
    def __init__(self):
        print "third"

Third 的 MRO 应该是 [First, Second] 还是 [Second, First] ?没有明显的期望,Python 将引发错误:

 TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution order (MRO) for bases Second, First

为什么上面的示例缺少 super() 调用?这些示例的目的是展示 MRO 是如何构建的。它们 无意 打印 "first\nsecond\third" 或其他内容。您可以——当然应该尝试这个示例,添加 super() 调用,看看会发生什么,并更深入地了解 Python 的继承模型。但我的目标是保持简单并展示 MRO 是如何构建的。它是按照我的解释建造的:

 >>> Fourth.__mro__
(<class '__main__.Fourth'>,
 <class '__main__.Second'>, <class '__main__.Third'>,
 <class '__main__.First'>,
 <type 'object'>)

原文由 rbp 发布,翻译遵循 CC BY-SA 4.0 许可协议

您的代码和其他答案都是错误的。他们缺少合作子类工作所需的前两个类中的 super() 调用。更好的是:

 class First(object):
    def __init__(self):
        super(First, self).__init__()
        print("first")

class Second(object):
    def __init__(self):
        super(Second, self).__init__()
        print("second")

class Third(First, Second):
    def __init__(self):
        super(Third, self).__init__()
        print("third")

输出:

 >>> Third()
second
first
third

super() 调用在每一步都在 MRO 中找到下一个方法,这就是为什么 FirstSecond 也必须停止执行的原因--- Second.__init__()


没有 super() second First Second

 >>> Third()
first
third

原文由 lifeless 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题