【问题标题】:Python: Calling multiple inits in Multiple inheritancePython:在多重继承中调用多个初始化
【发布时间】:2019-02-17 01:43:04
【问题描述】:

我有 2 个类:A(需要 1 个参数来初始化)和 B(需要 2 个参数来初始化),以及派生自 A 和 B 的第三类 C。

class A:
    def __init__(self, sval): 
        print("A: rcd value: ", sval)
        self.aval = sval

class B: 
    def __init__(self, sval, tval):
        print("B: rcd 2 values: ", sval, tval)
        self.aval=sval
        self.bval=tval

class C(A,B):
    def __init__(self, a, b, c):
        super().__init__(a) 
        super().__init__(b,c) # error here

c = C(1,2,3)

当我运行上面的代码时,最后一行有错误;调用的是 A 类的 __init__,而不是 B 类的。

A: rcd value:  1
Traceback (most recent call last):
  File "inheritance.py", line 20, in <module>
    c = C(1,2,3)
  File "inheritance.py", line 16, in __init__
    super().__init__(b,c) 
TypeError: __init__() takes 2 positional arguments but 3 were given

如何从 C 类的 __init__ 调用 A 和 B 的 __init__ 函数?

编辑:我在 Debian Linux 上使用 Python 3.5.3,但我更喜欢同时适用于 Python2 和 Python3 的解决方案。

【问题讨论】:

  • 我添加了 Python-2.xPython-3.x 标签,因为您从未指定您使用的 Python 版本,并且该解决方案适用于两者
  • 您有一个冲突需要解决:AB 都有名为 aval 的属性;一个需要重命名。如果您无法控制AB,那么您将不得不为其中一个定义一个适配器。
  • 使用super的正确方法是同时使用AB,然后使用super 一次 from C.__init__

标签: python python-3.x oop python-2.x multiple-inheritance


【解决方案1】:

假设您可以控制AB,并且可以避免在两者中使用相同的属性名称。那么为了正确使用super,定义如下。

class A:
    def __init__(self, aval, **kwargs): 
        print("A: rcd value: ", aval)
        self.aval = sval
        super().__init__(**kwargs)

class B: 
    def __init__(self, b1val, b2val, **kwargs):
        print("B: rcd 2 values: ", b1val, b2val)
        self.b1val = b1val
        self.b2val = b2val
        super().__init__(**kwargs)

那么C.__init__只需调用super一次

class C(A, B):
    def __init__(self, aval, b1val, b2val, **kwargs):
        super().__init__(aval=aval, b1val=b1val, b2val=b2val, **kwargs)

c = C(1, 2, 3)

【讨论】:

  • AK47 的解决方案有什么缺点吗?
  • 至少按照书面规定,它不处理AB 中定义的冲突aval 属性; B.__init__ 只是覆盖A.__init__ 设置的值。此外(再次将其扩展到原始问题之外)如果 AB 共享一个公共基类,则它的 __init__ 方法(假设 AB 都正确调用它)将被调用两次,这可能导致问题,具体取决于其定义。
  • 最后,两种方法都需要注意所涉及的类是如何定义的。我永远不会说显式调用父类方法而不是使用super 是绝对错误;您只需要了解每种方法的优缺点,并使用最适合您的类层次结构的一种即可。
  • 很好的解释。我认为您可以将这些 cmets 放在自己的答案中,其他用户更有可能阅读它们。
【解决方案2】:

调用A.__init__()B.__init__() 而不是super().__init__()

class C(A,B):
    def __init__(self, a, b, c):
        A.__init__(self, a) 
        B.__init__(self, b, c)

Python 3 (https://repl.it/repls/CooperativeTransparentRobot):

class A:
    def __init__(self, sval): 
        print("A: rcd value: ", sval)
        self.aval = sval

class B: 
    def __init__(self, sval, tval):
        print("B: rcd 2 values: ", sval, tval)
        self.aval=sval
        self.bval=tval

class C(A,B):
    def __init__(self, a, b, c):
        A.__init__(self, a) 
        B.__init__(self, b,c) # this does not give error

c = C(1,2,3)

>> Python 3.6.1 (default, Dec 2015, 13:05:11)
>> [GCC 4.8.2] on linux
>> A: rcd value:  1
>> B: rcd 2 values:  2 3

也适用于 Python 2: https://repl.it/repls/GreenAbleBlockchain

【讨论】:

  • 我可以保留第一个超级呼叫:super().__init__(a) 并且只使用B.__init__(self, b, c) 吗?
  • 可以,但不要将self 传递给super().__init__()
  • 我更改了之前给出错误的行的注释。这种方法效果很好,但@chepner 的回答似乎基础更广泛。
  • @AK47 请注意,当您调用B.__init__ 时,它会覆盖A.__init__ 设置的aval。显式使用 A.__init__B.__init__ 并不是真正的问题,只是 C 从两个冲突的类继承。
猜你喜欢
  • 2020-07-30
  • 2013-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-09
  • 2018-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多