python多继承使用super将构造函数传递给参数

python multiple inheritance passing arguments to constructors using super

考虑下面的python代码片段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A(object):
    def __init__(self, a):
        self.a = a

class B(A):
    def __init__(self, a, b):
        super(B, self).__init__(a)
        self.b = b

class C(A):
    def __init__(self, a, c):
        super(C, self).__init__(a)
        self.c = c

class D(B, C):
    def __init__(self, a, b, c, d):
        #super(D,self).__init__(a, b, c) ???
        self.d = d

我想知道如何将abc传递给相应的基类构造函数。

谢谢,


通常,当处理多个继承时,您的基类(不幸的是)应该设计为多个继承。在您的示例中,类BC不是,因此您找不到合适的方法将super应用到D中。

为多继承设计基类的一种常见方法是让中间层的基类在它们的__init__方法中接受它们不打算使用的额外参数,并将它们传递给它们的super调用。

在python中有一种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A(object):
    def __init__(self,a):
        self.a=a

class B(A):
    def __init__(self,b,**kw):
        self.b=b
        super(B,self).__init__(**kw)

 class C(A):
    def __init__(self,c,**kw):
        self.c=c
        super(C,self).__init__(**kw)

class D(B,C):
    def __init__(self,a,b,c,d):
        super(D,self).__init__(a=a,b=b,c=c)
        self.d=d

这可以被视为令人失望,但事实就是如此。


不幸的是,如果不更改基类,就无法使用super()来实现这一点。调用BC的构造函数将尝试调用方法解析顺序中的下一个类,该类始终是BC类,而不是BC类构造函数假定的A类。

另一种方法是显式调用构造函数,而不在每个类中使用super()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A(object):
    def __init__(self, a):
        object.__init__()
        self.a = a

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

class C(object):
    def __init__(self, a, c):
        A.__init__(self, a)
        self.c = c

class D(B, C):
    def __init__(self, a, b, c, d):
        B.__init__(self, a, b)
        C.__init__(self, a, c)
        self.d = d

这里仍然存在一个缺点,因为A构造函数将被调用两次,在本例中,这实际上没有太大的效果,但会导致更复杂的构造函数出现问题。可以包含一个检查,以防止构造函数运行多次。

1
2
3
4
5
class A(object):
    def __init__(self, a):
        if hasattr(self, 'a'):
            return
        # Normal constructor.

有些人会称之为EDOCX1的缺点(0),从某种意义上说,这是缺点,但一般来说,这只是多重继承的缺点。菱形继承模式通常容易出错。很多解决方法会导致代码更加混乱和容易出错。有时,最好的答案是尝试重构代码以使用较少的多重继承。