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

Ale*_*ber 15 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):
        ?
Run Code Online (Sandbox Code Playgroud)

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

我试过了

class AB(A,B):
    def __init__( self, x, y, z=0):
        A.__init__(x,y)
        B.__init__(z)
Run Code Online (Sandbox Code Playgroud)

但这给了我一个错误.

ovg*_*vin 15

其他答案建议添加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)
Run Code Online (Sandbox Code Playgroud)

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

>>> AB.__mro__
(<class '__main__.AB'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
Run Code Online (Sandbox Code Playgroud)

看,这就是第一AB__init__调用,那么B的,那么A的,然后object的.

让我们检查:

>>> ab = AB(1)
__init__ is called in AB
__init__ is called in B
__init__ is called in A
Run Code Online (Sandbox Code Playgroud)

但通过这个链条的这些调用是由super.当我们输入时super(AB, self),它意味着:AB__mro__链中找到下一个类self.

那么,我们应该调用superB,寻找后链中的下一类B:super(B, self).

使用super而不是手动调用A.__init__(self,...)等很重要,因为它可能会导致以后出现问题.阅读本文以获取更多信息.

所以,如果你坚持下去super,那就有问题了.__init__类中的方法需要不同的参数.并且您无法确定super将在这些类中调用方法的顺序.顺序由类算法创建时的C3算法确定.在子类中,另一个类可能介于调用链之间.因此,您不能拥有不同的参数__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
Run Code Online (Sandbox Code Playgroud)

所以我认为delegation在这里考虑使用而不是继承是个好主意.

class AB(object):
    def __init__(self, x, y, z=0):
        self.a = A(x,y)
        self.b = B(z)
Run Code Online (Sandbox Code Playgroud)

因此,您只需在对象内创建ab实例ABAB.然后可以通过参考self.a和方法通过方法使用它们self.b.

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


use*_*ica 13

你没有通过self.

class AB(A, B):
    def __init__(self, x, y, z=0):
        A.__init__(self, x, y)
        B.__init__(self, z)
Run Code Online (Sandbox Code Playgroud)

请注意,如果此继承层次结构变得更复杂,则会遇到构造函数未执行或重新执行的问题.考虑super(和问题super),不要忘记要继承object如果你在2.x和你的类不从别的继承.