使用super()进行直接多重继承时保持可读性

问题描述 投票:1回答:2

对于最基本的多重继承的情况:

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处理传递参数,但又是钻石继承。

python multiple-inheritance
2个回答
1
投票

在这里使用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__,该签名提到初始化所需的两个参数AB。使用C1C1.__init__没有定义所以A.__init__将被调用。使用C2,您需要在链中明确调用下一个__init__方法。

C,知道它是AB的子类,必须至少为已知的上游__init__方法提供预期的论据。

A.__init__将把除a之外的所有东西传递给下一个班级的__init__方法。

除了B.__init__b将传递它收到的一切。

最终将调用object.__init__,并假设所有先前的类正确删除了它们引入的关键字参数,将不会收到任何其他参数。

更改调用各种__init__s的顺序意味着更改MRO,这意味着更改基类的顺序。如果你想要更多的控制,那么合作多重继承不适合你。


0
投票
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
© www.soinside.com 2019 - 2024. All rights reserved.