2009-05-24 22 views
242

これを考える - 基本クラスA、Bを継承するクラスC、コンストラクタで親クラスのコンストラクタを呼び出す一般的な方法は何ですか?まだあまりにも曖昧に聞こえる場合は、ここにいくつかのコードがあります。Pythonの連鎖呼び出し親コンストラクタ

class A(object): 
    def __init__(self): 
     print "Constructor A was called" 

class B(A): 
    def __init__(self): 
     super(B,self).__init__() 
     print "Constructor B was called" 

class C(B): 
    def __init__(self): 
     super(C,self).__init__() 
     print "Constructor C was called" 

c = C() 

これは私が今やっている方法です。しかし、それはまだあまりにも一般的ではないように思えます - あなたは手で正しいタイプを渡す必要があります。

ここでは、super()の最初の引数としてself.__class__を使用しようとしましたが、明らかに動作しません。Cのコンストラクタに入れた場合、Bのコンストラクタが呼び出されます。 Bで同じことをすると、 "self"はCのインスタンスを指しているので、Bのコンストラクタをもう一度呼び出すことになります(これは無限回帰で終了します)。

今のところダイヤモンドの継承について考える必要はありません。私はこの特定の問題を解決することに興味があります。

+0

を「しかし、それはまだ少しあまりにも非ジェネリックようだ - あなたは手で正しいタイプを渡す必要があります。 "クラス名をsuper()に渡しています。あなたはスーパークラスか何かを知る必要はありません。これは非一般的な仕組みですか?どのような問題が生じますか?これが壊れた例を挙げることができますか? –

+3

私はこの質問に答える準備ができていません。しかし、とにかく、クラス名を変更するとどうなるでしょうか?このような連鎖を自動化するデコレータ関数を記述したいのですが?今、私はこれが不可能だが、質問するときに私はそれを知らなかったことを知る。 – shylent

答えて

151

あなたがやっていることは確かに推奨されています(Python 2.xの場合)。

クラスが明示的にsuperに渡されるかどうかの問題は、機能ではなくスタイルの問題です。クラスをsuperに渡すことは、Pythonの "explicitは暗黙的より優れている"という理念に適合します。

+3

私は受け入れる答えを決めるのに本当に苦労しましたが、私が使っているPythonのバージョンに関連しているので、これを受け入れます。 – shylent

+9

Python 2.6では、このメソッドを使って 'TypeError:super()引数1が型で、classobjではなくてはなりません。 'というメッセージが表示されます。何か不足していますか? – Leopd

+12

@Leopd: 'super()'は新しいスタイルのクラスでしか動作しません。つまり、 'object'から継承する必要があります。 –

159

次のように使うことができますPythonの3の改善スーパーを(含んで):

super().__init__(args) 
+0

を参照してください。どの親クラスを呼び出すべきかをsuperで識別する – Kracekumar

+2

@kracekumarクラスのメソッド解決順序(MRO)によって決定されます。これは、 'MyClassName.mro()'を呼び出すことによって見つけることができます。私は間違っているかもしれませんが、最初に指定された親は '__init__'が呼び出される親であると信じています。 –

+0

@ironfroggy、あなたは精巧に思うでしょうか?私はちょうどこの古いスレッドを見つけ、私は同じ正確な質問をしています。また、この質問が最初に尋ねられて以来、Python 2.xのために改良されたことがありますか? –

22

あなたは簡単に書くことができます。

class A(object): 

    def __init__(self): 
     print "Constructor A was called" 

class B(A): 

    def __init__(self): 
     A.__init__(self) 
     # A.__init__(self,<parameters>) if you want to call with parameters 
     print "Constructor B was called" 

class C(B): 

    def __init__(self): 
     # A.__init__(self) # if you want to call most super class... 
     B.__init__(self) 
     print "Constructor C was called" 
関連する問題