class A(object): # A must be new-style class def __init__(self): print "enter A" print "leave A" class B(C): # A --> C def __init__(self): print "enter B" super(B, self).__init__() print "leave B"
私たちの印象では、 super(B, self).__init__() は次のように理解されます: super(B, self) は、まず B の親クラス (つまり、クラス A) を見つけて、次にクラスを配置します。 B into オブジェクト self がクラス A のオブジェクトに変換され、「変換された」クラス A オブジェクトが独自の __init__ 関数を呼び出します。
ある日、同僚が比較的複雑なクラス アーキテクチャを設計しました (クラス アーキテクチャが合理的に設計されているかどうかは気にせず、この例をトピックとして学習してください)。コードは次のとおりです
コード セグメント 4:
class A(object): def __init__(self): print "enter A" print "leave A" class B(object): def __init__(self): print "enter B" print "leave B" class C(A): def __init__(self): print "enter C" super(C, self).__init__() print "leave C" class D(A): def __init__(self): print "enter D" super(D, self).__init__() print "leave D" class E(B, C): def __init__(self): print "enter E" B.__init__(self) C.__init__(self) print "leave E" class F(E, D): def __init__(self): print "enter F" E.__init__(self) D.__init__(self) print "leave F"
f = F() 、結果は次のようになります:
enter F enter E enter B Leave B enter C enter D enter A left A Leave D Leave C Leave E enter D enter A Leave A Leave D Leave F
明らかに、クラス A とクラス D の初期化関数が 2 回呼び出されており、これは私たちが期待した結果ではありません。予想される結果は、クラス A の初期化関数が最大 2 回呼び出されるということです。実際、これは多重継承クラス システムが直面しなければならない問題です。以下に示すように、コード セグメント 4 のクラス システムを描画します。図からわかるように、クラス C の初期化関数が呼び出されるとき、クラス A の初期化関数は次のようにする必要があります。と呼ばれていますが、実際にはクラス D の初期化関数が呼び出されます。なんて奇妙な質問でしょう!
言い換えると、mro はクラスのすべての基本クラスのクラス型シーケンスを記録します。 mro のレコードを見ると 7 つの要素が含まれており、その 7 つのクラス名は次のとおりです:
F E B C D A object
C.__init__ で super(C, self).__init__() を使用するとクラス D が呼び出される理由がこれで説明されています。初期化関数。 ???
コード セグメント 4 を次のように書き換えます:
コード セグメント 5:
class A(object): def __init__(self): print "enter A" super(A, self).__init__() # new print "leave A" class B(object): def __init__(self): print "enter B" super(B, self).__init__() # new print "leave B" class C(A): def __init__(self): print "enter C" super(C, self).__init__() print "leave C" class D(A): def __init__(self): print "enter D" super(D, self).__init__() print "leave D" class E(B, C): def __init__(self): print "enter E" super(E, self).__init__() # change print "leave E" class F(E, D): def __init__(self): print "enter F" super(F, self).__init__() # change print "leave F"
f = F()、実行結果:
enter F enter E enter B enter C enter D enter A left A Leave D Leave C Leave B Leave E Leave F
F の初期化により、すべての親クラスの呼び出しが完了するだけでなく、各親クラスの初期化関数が 1 回だけ呼び出されることがわかります。
概要 1. Superは関数ではなく、クラス名です super(B, self)という形式は、実際にはスーパークラスの初期化関数を呼び出し、スーパーオブジェクトを生成します。 class 初期化関数は特別な操作を行わず、単にクラスの型と特定のインスタンスを記録します
3. super(B, self).func への呼び出しは、現在の親クラスの func 関数を呼び出すために使用されません。 class;4. Python の多重継承クラスは、各親クラスの関数が 1 つずつ呼び出されることを保証し、各親クラスの関数が 1 回だけ呼び出されることを保証します (各クラスが super を使用する場合)。スーパークラスと非バインディング関数は危険な動作であり、呼び出されるはずの親クラス関数が呼び出されなかったり、親クラス関数が複数回呼び出されたりする可能性があります。
さらに詳しい質問: ご覧のとおり、F.__mro__ を出力すると、内部の要素の順序は F E B C D A オブジェクトであることがわかります。これは F の基本クラスの検索順序です。なぜこのようになるのかについてです。 order、および Python の組み込み多重継承 シーケンスの実装方法、これには mro シーケンスの実装が含まれます