对于最基本的多重继承的情况:
class A:
def __init__(self, a):
self.a = a
class B:
def __init__(self, b):
self.b = b
class C(A, B):
def __init__(self, a, b):
A.__init__(self, a)
B.__init__(self, b)
我不明白为什么要使用super()
。我想你可以用kwargs实现它,但这肯定比上面的方法更不易读。我还没有找到有关这种方法的堆栈溢出的任何答案,但对于这种情况肯定是最令人满意的?
在这个主题上有很多问题被标记为重复,但对于这个确切的案例没有令人满意的答案。 This question解决了多重继承问题以及使用super()
进行钻石继承。在这种情况下,没有钻石继承,父类也没有彼此的任何知识,所以他们不应该像super()
建议的那样调用this。
This answer在这种情况下处理super
的使用,但没有像__init__
那样传递参数,而this answer处理传递参数,但又是钻石继承。
在这里使用super
的一种正确方法是
class A:
def __init__(self, a, **kwargs):
super().__init__(**kwargs)
self.a = a
class B:
def __init__(self, b, **kwargs):
super().__init__(**kwargs)
self.b = b
class C1(A, B):
pass
class C2(A, B):
def __init__(self, a, b, **kwargs):
super().__init__(a=a, b=b, **kwargs)
c1 = C1(a="foo", b="bar")
c2 = C2(a="foo", b="bar")
C
的方法解析顺序是[C, A, B, object]
。每次调用super()
时,它都会根据当时调用super()
的位置返回MRO中下一个类的代理。
定义C
时有两个选项,具体取决于您是否要使用签名定义C.__init__
,该签名提到初始化所需的两个参数A
和B
。使用C1
,C1.__init__
没有定义所以A.__init__
将被调用。使用C2
,您需要在链中明确调用下一个__init__
方法。
C
,知道它是A
和B
的子类,必须至少为已知的上游__init__
方法提供预期的论据。
A.__init__
将把除a
之外的所有东西传递给下一个班级的__init__
方法。
除了B.__init__
,b
将传递它收到的一切。
最终将调用object.__init__
,并假设所有先前的类正确删除了它们引入的关键字参数,将不会收到任何其他参数。
更改调用各种__init__
s的顺序意味着更改MRO,这意味着更改基类的顺序。如果你想要更多的控制,那么合作多重继承不适合你。
class A(object):
def __init__(self, *args, **kwargs):
super(A, self).__init__(*args, **kwargs)
self.a = kwargs['a']
class B(object):
def __init__(self, *args, **kwargs):
super(B, self).__init__()
self.b = kwargs['b']
class C(A, B):
def __init__(self, *args, **kwargs):
super(C, self).__init__(*args, **kwargs)
z = C(a=1,b=2)
z.b
2