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

Maintaining readability when using super() for direct multiple inheritance

对于最基本的多重继承:

1
2
3
4
5
6
7
8
9
10
11
12
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实现它,但是这肯定比上面的方法更不可读。我还没有找到任何支持这种方法的关于堆栈溢出的答案,但对于这种情况,这肯定是最令人满意的吗?

在这个问题上,有很多问题被标记为重复的,但是对于这个确切的案例,没有令人满意的答案。这个问题涉及多重继承和使用super()进行钻石继承。在这种情况下,没有菱形继承,父类之间也没有任何知识,因此它们不需要像这样调用super()

这个答案处理在这个场景中使用super,但不向__init__传递参数,就像这里所做的那样,这个答案处理传递参数,但又是一个菱形继承。


这里正确使用EDOCX1[0]的方法是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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两个参数。使用C1,没有定义C1.__init__,因此将调用A.__init__。使用C2时,需要显式调用链中的下一个__init__方法。

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

A.__init__将把除A以外的所有东西传递给下一个类的__init__方法。

B外,B.__init__将把它收到的所有东西都传出去。

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

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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