web-dev-qa-db-ja.com

python superを使用してコンストラクタに引数を渡す多重継承

pythonコードの次のスニペットを検討してください

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

ab、およびcを対応する基本クラスのコンストラクターに渡すにはどうすればよいでしょうか。

34
Lin

まあ、一般に多重継承を扱うとき、基本クラスは(残念ながら)多重継承用に設計されたでなければなりません。あなたの例のクラスBCはそうではないので、superDを適用する適切な方法を見つけることができませんでした。

多重継承用の基本クラスを設計する一般的な方法の1つは、中間レベルの基本クラスが、使用しない__init__メソッドで追加の引数を受け入れ、それらをsuperに渡すことです。コール。

Pythonでそれを行う1つの方法を次に示します。

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

これは期待はずれと見ることができますが、それはまさにそうです。

46
shx2

残念ながら、Baseクラスを変更せずにsuper()を使用してこの作業を行う方法はありません。 BまたはCのコンストラクターへの呼び出しは、 メソッド解決順序 の次のクラスを試行し、呼び出します。これは、BおよびCクラスコンストラクターのAクラスではなく、常にBまたはCになります仮定します。

別の方法は、各クラスでsuper()を使用せずにコンストラクターを明示的に呼び出すことです。

_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コンストラクターが2回呼び出されるため、ここにはまだ欠点があります。これは、この例ではあまり効果がありませんが、より複雑なコンストラクターで問題を引き起こす可能性があります。コンストラクターが複数回実行されるのを防ぐために、チェックを含めることができます。

_class A(object):
    def __init__(self, a):
        if hasattr(self, 'a'):
            return
        # Normal constructor.
_

ある人はこれをsuper()の欠点と呼びますが、それはある意味ではありますが、一般に多重継承の欠点でもあります。ダイヤモンドの継承パターンは、多くの場合エラーを起こしやすいです。そして、それらの回避策の多くは、さらに混乱を招き、エラーを起こしやすいコードにつながります。最良の答えは、コードをリファクタリングして多重継承を少なくすることです。

9
Brendan Abel