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

时间:2019-02-07 18:17:38

标签: python multiple-inheritance

对于最基本的多重继承:

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()用于钻石继承问题。在这种情况下,没有钻石继承,并且父类也没有彼此的知识,因此他们不需要像this那样调用super()

在这种情况下,

This answer处理super的使用,但不像在此那样将参数传递给__init__,而this answer处理传递的参数,但又是一个钻石继承。

2 个答案:

答案 0 :(得分: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中 next 类的代理。

定义C时有两个选择,这取决于是否要定义带有签名的C.__init__签名,该签名提及初始化所需的两个参数AB。对于C1C1.__init__未定义,因此将调用A.__init__。使用C2,您需要显式调用链中的下一个__init__方法。

C知道它是AB的子类,因此必须至少为已知的上游__init__方法提供期望的参数。

A.__init__会将所有 a传递给下一类的__init__方法。

B.__init__将传递其所有 接收的内容,除了b

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

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

答案 1 :(得分: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