23
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)

しかし、これは私にエラーを与えます。

4

2 に答える 2

25

他の回答は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__呼び出され、次に が呼び出され、次に が呼び出され、次に が呼び出さBAますobject

確認しよう:

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

しかし、このチェーンを介したこれらの呼び出しは によって行われsuperます。と入力するsuper(AB, self)と、次の意味にABなり__mro__ますself

super次に、 inを呼び出して、チェーン内の:Bの後の次のクラスを探します。Bsuper(B, self)

後で問題が発生する可能性があるため、super手動で呼び出すなどしないで使用することが重要です。詳細については、これをお読みくださいA.__init__(self,...)

したがって、そのままにしsuperておくと、問題が発生します。__init__あなたのクラスのメソッドは異なるパラメータを期待しています。superまた、これらのクラスのメソッドを呼び出す順序を確実に知ることはできません。順序は、クラス作成時にC3 アルゴリズムによって決定されます。サブクラスでは、別のクラスが呼び出しチェーンの中間に入る場合があります。この場合、メソッドがどのように呼び出される__init__かを理解するために、常にすべての継承チェーンを考慮する必要があるためです。__init__

たとえば、それらのクラスとC(A)サブクラスを追加することを検討してください。Thenは afterではなく afterで呼び出されます。D(B)CDABC

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クラスを作成するだけです。ABそして、 と を参照してメソッドを介して必要に応じて使用できself.aますself.b

委任を使用するかどうかは、質問からは明らかでないケースによって異なります。しかし、それは考慮すべきオプションかもしれません。

于 2013-08-02T00:00:42.873 に答える