多重继承和调用 super()

Posted

技术标签:

【中文标题】多重继承和调用 super()【英文标题】:Multiple Inheritance and calling super() 【发布时间】:2017-07-30 19:31:28 【问题描述】:

我得到错误: TypeError: __init__() 正好接受 2 个参数(给定 3 个)

尝试从 Top 类实例化对象时:

super(Middle1, self).__init__(name, "middle")

class Base(object):
    def __init__(self, name, type):
        pass

class Middle1(Base):
    def __init__(self, name):
        super(Middle1, self).__init__(name, "middle1")

class Middle2(Base):
    def __init__(self, name):
        super(Middle2, self).__init__(name, "middle2")

class Middle3(Base):
    def __init__(self, name):
        super(Middle3, self).__init__(name, "middle3")

class Top(Middle1, Middle2, Middle3):
    def __init__(self):
        super(Top, self).__init__("top")

# Here is where it produces the error
if __name__ == '__main__':
    Top()

我对这个多重继承问题有什么不明白的地方?

注意:这是python 2.7

编辑

好的,所以我尝试了一些我认为适合我的情况的方法。这是等效的最终结果,我认为它基本上是通过不调用 super 而是调用每个单独的 __init__ 来强制深度优先。

class Base(object):
    def __init__(self, name, type):
        pass

class Middle1(Base):
    def __init__(self, name, type = "middle1"):
        super(Middle1, self).__init__(name, type)

class Middle2(Base):
    def __init__(self, name, type = "middle2"):
        super(Middle2, self).__init__(name, type)

class Middle3(Base):
    def __init__(self, name, type = "middle3"):
        super(Middle3, self).__init__(name, type)

class Top(Middle1, Middle2, Middle3):
    def __init__(self):
        Middle1.__init__(self, "top")
        Middle2.__init__(self, "top")
        Middle3.__init__(self, "top")

# No errors anymore
if __name__ == '__main__':
    Top()

【问题讨论】:

这在技术上不是多重继承。多重继承是指一个类直接从多个父类继承(大多数编程语言通常不支持)。 您检查过您正在执行的代码文件就是您在此处显示的那个吗?因为这段代码不会产生那个错误...... 你是对的。我已经编辑了代码以显示我的实际情况,现在它会产生该错误。 我也会向您推荐***.com/questions/3277367/… 这个问题。 (您的问题可能应该作为这个问题的副本关闭,但我认为基于您的特定代码的答案很有用,当我自己提供答案时,我犹豫使用我的欺骗锤单方面关闭问题。) 这与建议的问题略有不同。如果父母都收到相同的论点,我的会起作用。 【参考方案1】:

首先得看Top的方法解析顺序:

>>> for c in Top.__mro__: print c
...
<class '__main__.Top'>
<class '__main__.Middle1'>
<class '__main__.Middle2'>
<class '__main__.Middle3'>
<class '__main__.Base'>
<type 'object'>

这有助于您查看每个对 super 的调用代表哪个类。

您的错误是认为对super(Middle1, self) 的调用指的是Middle1 的(唯一)基类Base。不是:它指的是self.__class__ 的MRO 中Middle1 之后的类。因为self.__class__Top,所以下一个类是Middle2,其__init__ 只接受一个参数。

要从方法中正确使用super,您需要确保该方法在每个类中采用相同的参数,因为您无法通过查看代码来预测将调用哪个类的方法本身;它完全取决于启动调用链的对象的类型,这可能是一个你甚至还不知道的类。

我建议阅读两篇文章:

Python's super() considered super! Python's Super is nifty, but you can't use it很仔细地理解super的语义。

它们一起让您很好地了解何时可以正确使用 super 以及如何避免您在此处看到的问题。

(完全披露,我最近没有阅读任何一篇文章,所以我不会试图总结每篇文章中提出的建议。)

【讨论】:

是的,主要是这样,我希望它先深入,然后从左到右。 在每个类中为 __init__ 采用相同的参数是不够的,因为 object.__init__ 不采用任何参数,因此将参数传递给 super.__init__() 被破坏。见Super() and changing the signature of cooperating methods 我包含的链接还讨论了从对super().__init__(或其他上游方法)的调用中删除参数以避免该问题。【参考方案2】:

您具体是如何实例化 Top 对象的?

鉴于您上面的代码,以下工作正常:

   topObj = Top()
   middleObj = Middle("middle")
   baseObj = Base("base", "type")

【讨论】:

我看到你编辑了你的示例代码。事实上,使用多重继承构造函数解析变得令人困惑。

以上是关于多重继承和调用 super()的主要内容,如果未能解决你的问题,请参考以下文章

多重继承如何与 super() 和不同的 __init__() 参数一起工作?

超级混乱的python多重继承 super()

Python多重继承引发的问题——牛逼的super

Python 的 super() 如何与多重继承一起工作?

python多重继承的属性和方法调用顺序问题和对迭代器的初步理解

多重继承中无用的超级? [复制]