2012-01-18 15 views
14

組み込み型から、そして他のいくつかのクラスから派生するとき、組み込み型のコンストラクタはスーパークラスコンストラクタを呼び出さないようです。この結果、__init__メソッドは、MROの組み込み関数の後ろにある型に対して呼び出されません。Python 3の組み込み型__init__は、super().__ init__を呼び出しません。

例:このサンプルで

class A: 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     print("A().__init__()") 

class B(list, A): 
    def __init__(self, *args, **kwargs): 
     print("B().__init__() start") 
     super().__init__(*args, **kwargs) 
     print("B().__init__() end") 

if __name__ == '__main__': 
    b = B() 

は、A .__ init__が呼び出されることはありません。 Bがclass B(A, list)と定義されている場合(継承順序を切り替える)、意図したとおりに動作します(つまり、A .__ init__が呼び出されます)。

この非常に微妙な継承の依存関係は、むしろ非平凡なように見えますが、これはこのように意図されていますか?また、他の誰かがあなたのクラスから派生したとき(メンテナンスホラー)に、組み込み関数がどこでMROに終わるのかを知ることができないので、複雑なクラス階層の組み込み型から決して派生してはいけません。何か不足していますか?

追加情報:Pythonのバージョン3.1

+0

Pythonのそれはとinit__' 'A .__呼ぶもの__init__'方法 – Marcin

+2

'スーパークラスの自動呼び出しがありませんでしたか? 'list .__ init__'は1つの引数を取り、それ以上取得したらエラーを投げます。他の議論を受け入れたとしても、それは最初のものを駄目にするので、A sawは相続命令に依存するでしょう。 –

+0

同様の質問:http:// stackoverflow。com/questions/3277367/how-does-pythons-super-work-with-multiple-inheritance Guidoがその質問の答えから抜け出すのは:http://python-history.blogspot.com/2010/06/method- resolution-order.html – aganders3

答えて

9

super()の正しい使い方はかなり微妙であるとの連携方法は同じシグネチャを持っていない場合、すべてのいくつかの注意が必要です。これは、すべてのメソッドが協力することを必要とし、すべてのメソッドは、メソッドが呼び出された時点では重要ではありません確実にするために多少互換性の署名を必要とすること

class A(object): 
    def __init__(self, param_a, **kwargs): 
     self.param_a = param_a 
     super(A, self).__init__(**kwargs) 

class B(A): 
    def __init__(self, param_b, **kwargs): 
     self.param_b = param_b 
     super(B, self).__init__(**kwargs) 

class C(A): 
    def __init__(self, param_c, **kwargs): 
     self.param_c = param_c 
     super(C, self).__init__(**kwargs) 

class D(B, C): 
    def __init__(self, param_d, **kwargs): 
     self.param_d = param_d 
     super(D, self).__init__(**kwargs) 

d = D(param_a=1, param_b=2, param_c=3, param_d=4) 

注:__init__()方法のための通常のパターンは次のようです。

組み込み型のコンストラクタには、このようなコラボレーションに参加できるコンストラクタシグネチャがありません。たとえ彼らがsuper().__init__()と呼んでも、すべてのコンストラクタシグネチャが統一されていない限り、これはむしろ役に立たないでしょう。結局あなたは正しいのですが、彼らは協力的なコンストラクターコールの参加には向いていません。

super()は、すべての共同作業方法の署名が同じ場合(例:__setattr__())、上記(または類似の)パターンを使用する場合にのみ使用できます。ただし、super()を使用することは、基本クラスのメソッドを呼び出す唯一のパターンではありません。複数の継承パターンに「菱形」がない場合は、明示的な基本クラス呼び出しを使用できます(例:B.__init__(self, param_a))。複数の基本クラスを持つクラスは、単に複数のコンストラクタを呼び出します。ダイヤモンドがあっても、__init__()が何度も何度も呼び出されても問題がなければ、明示的な呼び出しを使用することがあります。

コンストラクタにsuper()を使用する場合は、実際には複数の内装階層で組み込みタイプのサブクラス(objectを除く)を使用しないでください。さらにいくつかの読書:

関連する問題