使用不同的参数在python中调用超类构造函数

时间:2013-08-01 23:26:07

标签: python inheritance constructor arguments

class A():
    def __init__( self, x, y):
        self.x = x
        self.y = y

class B():
    def __init__( self, z=0):
        self.z = z  

class AB(A,B):
    def __init__( self, x, y, z=0):
        ?

如何使AB的构造函数使用正确的参数调用A和B的构造函数?

我试过

class AB(A,B):
    def __init__( self, x, y, z=0):
        A.__init__(x,y)
        B.__init__(z)

但这给了我一个错误。

2 个答案:

答案 0 :(得分:14)

其他答案建议将self添加到第一个参数。

但通常在父类中调用__init__super

考虑这个例子:

class A(object):
    def __init__(self, x):
        print('__init__ is called in A')
        self.x = x


class B(object):
    def __init__(self, *args, **kwargs):
        print('__init__ is called in B')
        super(B, self).__init__(*args, **kwargs)


class AB(B, A):
    def __init__(self, *args, **kwargs):
        print('__init__ is called in AB')
        super(AB, self).__init__(*args, **kwargs)

AB类包含应该调用构造函数和初始化器的顺序:

>>> AB.__mro__
(<class '__main__.AB'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)

请注意,先调用AB __init__,然后调用B,然后调用A,然后调用object

我们来看看:

>>> ab = AB(1)
__init__ is called in AB
__init__ is called in B
__init__ is called in A

但是通过这个链的这些调用是由super完成的。当我们输入super(AB, self)时,它意味着:在AB的{​​{1}}链__mro__之后找到下一个课程。

然后我们应该在self中调用super,在B之后查找链中的下一个类:B

使用super(B, self)而不是手动调用super等非常重要,因为它可能会在以后导致问题。 Read this for more info

所以,如果你坚持A.__init__(self,...),那就有问题了。类中的super方法需要不同的参数。而且您无法确定__init__将在这些类中调用方法的顺序。在创建课程时,顺序由C3 algorithm确定。在子类中,另一个类可能介于调用链之间。因此,super中不能有不同的参数,因为在这种情况下,您将始终考虑所有继承链,以了解如何调用__init__方法。

例如,考虑添加__init__C(A)类以及它们的D(B)子类。然后,在CD之后,A之后将不再调用B

C

所以我认为考虑在这里使用class A(object): def __init__(self, *args, **kwargs): print('__init__ is called in A') super(A, self).__init__(*args, **kwargs) class B(object): def __init__(self, *args, **kwargs): print('__init__ is called in B') super(B, self).__init__(*args, **kwargs) class AB(B,A): def __init__(self, *args, **kwargs): print('__init__ is called in AB') super(AB, self).__init__(*args, **kwargs) class C(A): def __init__(self, *args, **kwargs): print('__init__ is called in C') super(C, self).__init__(*args, **kwargs) class D(B): def __init__(self, *args, **kwargs): print('__init__ is called in D') super(D, self).__init__(*args, **kwargs) class CD(D,C): def __init__(self, *args, **kwargs): print('__init__ is called in CD') super(CD, self).__init__(*args, **kwargs) class ABCD(CD,AB): def __init__(self, *args, **kwargs): print('__init__ is called in ABCD') super(ABCD, self).__init__(*args, **kwargs) >>> abcd = ABCD() __init__ is called in ABCD __init__ is called in CD __init__ is called in D __init__ is called in AB __init__ is called in B __init__ is called in C __init__ is called in A 而不是继承是个好主意。

delegation

因此,您只需在class AB(object): def __init__(self, x, y, z=0): self.a = A(x,y) self.b = B(z) 对象中创建ab个类的AB个实例。然后可以通过参考ABself.a

来通过方法使用它们

使用与否授权取决于您的案例,而您的问题并不明确。但这可能是一个考虑的选择。

答案 1 :(得分:12)

您没有通过self

class AB(A, B):
    def __init__(self, x, y, z=0):
        A.__init__(self, x, y)
        B.__init__(self, z)

请注意,如果此继承层次结构变得更复杂,则会遇到构造函数未执行或重新执行的问题。查看superproblemssuper),如果您使用的是object并且您的班级没有,请不要忘记继承{{1}}继承其他任何东西。