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
a
、b
、およびc
を対応する基本クラスのコンストラクターに渡すにはどうすればよいでしょうか。
まあ、一般に多重継承を扱うとき、基本クラスは(残念ながら)多重継承用に設計されたでなければなりません。あなたの例のクラスB
とC
はそうではないので、super
にD
を適用する適切な方法を見つけることができませんでした。
多重継承用の基本クラスを設計する一般的な方法の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
これは期待はずれと見ることができますが、それはまさにそうです。
残念ながら、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()
の欠点と呼びますが、それはある意味ではありますが、一般に多重継承の欠点でもあります。ダイヤモンドの継承パターンは、多くの場合エラーを起こしやすいです。そして、それらの回避策の多くは、さらに混乱を招き、エラーを起こしやすいコードにつながります。最良の答えは、コードをリファクタリングして多重継承を少なくすることです。