多重继承:第二个基类构造函数要求泄漏给第一个基类构造函数

时间:2018-10-10 16:34:17

标签: python multiple-inheritance

我正在尝试从2个基类继承。

第一个基类(Base1)构造函数不带参数:

class Base1(object):
    def __init__(self):
        ...

第二个基类(Base2)构造函数采用一个参数id

class Base2(object):
    def __init__(self, id):
        ...

在派生类中,我尝试依次调用每个基类构造函数:

class Deriv(Base1, Base2):
    def __init__(self):
        super(Base1, self).__init__()
        super(Base2, self).__init__("hello world")

此操作失败,并显示以下错误:

    super(Base1, self).__init__()
TypeError: __init__() missing 1 required positional argument: 'id'

如何正确调用每个基类构造函数及其正确的参数列表?

这是一个示例应用程序,可重现我遇到的错误:

#!/usr/bin/env python3

class Base1(object):
    def __init__(self):
        pass

class Base2(object):
    def __init__(self, id):
        self.id = id

class Deriv(Base1, Base2):
    def __init__(self):
        super(Base1, self).__init__()
        super(Base2, self).__init__("hello world")

def main():
    Deriv()

if __name__ == '__main__':
    main()

这是回溯:

Traceback (most recent call last):
  File "./test.py", line 20, in <module>
    main()
  File "./test.py", line 17, in main
    Deriv()
  File "./test.py", line 13, in __init__
    super(Base1, self).__init__()
TypeError: __init__() missing 1 required positional argument: 'id'

2 个答案:

答案 0 :(得分:1)

您在super上使用了错误的第一个参数:

def __init__(self):
    super(Deriv, self).__init__()
    super(Base1, self).__init__("Hello world")

但是请注意,这仅是因为Base1.__init__本身不使用super,因为这样做的话,它将尝试调用Base2.__init__,因为这是该方法中的下一个方法。原始对象的MRO。

super的第一个参数告诉您之后 MRO中的哪个类开始寻找所需的属性。

答案 1 :(得分:1)

您误解了super()的功能。 super()__mro__类型中获取self方法解析顺序属性(一个序列),然后找到该序列中第一个参数的位置,然后开始搜索过去那一点。

对于您的情况Deriv.__mro__是:

(<class '__main__.Deriv'>, <class '__main__.Base1'>, <class '__main__.Base2'>, <class 'object'>)

super(Base1, self)将开始在下一个对象__init__上搜索Base2方法,super(Base2, self)将找到object。由于Base2.__init__必须接受一个id自变量,但super(Base1, self).__init__()不提供该自变量,因此引发了错误。

您想改用协作继承,并向调用链传递参数:

class Base1(object):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

class Base2(object):
    def __init__(self, id, *args, **kwargs):
        self.id = id
        super().__init__(*args, **kwargs)

class Deriv(Base1, Base2):
    def __init__(self):
        super().__init__("hello world")

如果必须直接处理基类,则不要使用super(),而是直接调用未绑定的方法:

class Base1(object):
    def __init__(self):
        pass

class Base2(object):
    def __init__(self, id):
        self.id = id

class Deriv(Base1, Base2):
    def __init__(self):
        Base1.__init__(self)
        Base2.__init__(self, "hello world")