2

Python の C3 メソッドの解決順序について読んだとき、「子は親よりも優先され、サブクラスの順序は尊重される」と簡略化されているとよく耳にします。しかし、すべてのサブクラスが同じ祖先から継承されている場合にのみ、これが当てはまるようです。

例えば

class X():
    def FOO(self):
        return 11

class A(X):
    def doIt(self):
        return super().FOO()        
    def FOO(self):
        return 42

class B(X):
    def doIt(self):
        return super().FOO()        
    def FOO(self):
        return 52

class KID(A,B):
    pass

ここで、KID の MRO は次のとおりです。KID、A、B、X

ただし、 B を代わりに変更した場合:

class B(object):

KID の MRO は次のようになります: KID、A、X、B

すべての KID の親の検索を完了する前に、A のスーパークラスを検索しているようです。

したがって、「子供優先、幅優先」から「子供優先、共通の祖先の場合は幅優先」、そうでなければ深さ優先」よりも少し直感的ではないように思えます。

クラスが共通の祖先の使用を停止すると、MRO が変更され (その 1 つのリンクを除いて全体的な階層は同じですが)、そのクラスのメソッドではなく、より深い祖先メソッドを呼び出すようになるというのは、かなりの落とし穴です。

4

1 に答える 1

2

Python 3 のすべてのクラスには、共通の基本クラスobject. 定義からクラスを省略できますが、class既に から間接的に継承していない限り、存在しますobject。(Python 2 では、これは新しいスタイルのクラス機能であるobjectため、を使用するためにも明示的に継承する必要があります)。super()

の基底クラスをBからXに変更しましたobjectが、からX 継承していobjectます。MRO はこれを考慮して変更されました。C3 ルールの同じ単純化 (子は親の前に来て、サブクラスの順序が尊重される) はここでも適用できます。Bが の前objectに来てXABが同じ順序でリストされています。ただし、継承元とサブクラスの両方が の前に来るため、 の前にX来る必要があります。BobjectA(X)BKID

C3 が幅優先であるとはどこにも書かれていないことに注意してください。どちらかといえば深さ優先です。アルゴリズムの詳細な説明とそれが Python にどのように適用されるかについては、 The Python 2.3 Method Resolution Orderを参照してください。ただし、クラスの線形化は、基本クラスと基本クラス自体の線形化をマージした結果です。

L[KID] = KID + merge(L[A], L[B], (A, B))

L[..]そのクラスの C3 線形化 (MRO) はどこにありますか。

Aそのため、マージ時にはの線形化がB優先され、C3 は階層を幅ではなく深さで見るようになります。マージは一番左のリストから始まり、他のリストの末尾に表示されない要素 (つまり、最初の要素以外のすべて) を取得し、次に次のリストを取得します。

最初の例では、L[A]L[B]はほぼ同じです (両方とも(X, object)MRO として終了し、最初の要素のみが異なります)。したがって、マージは簡単です。と をマージ(A, X, object)(B, X, object)、これらをマージすると、最初のリストからのみが得られA、次に 2 番目のリスト全体が得られ、先頭に追加した(KID, A, B, X, object)後にKID:

L[KID] = KID + merge((A, X, object), (B, X, object), (A, B))
#                        ^  ^^^^^^
#                         \ & \ both removed as they appear in the next list
       = KID + (A,) + (B, X, object)
       = (KID, A, B, X, object)

2 番目の例では、L[A]is changedですが、L[B]現在は(B, object)(dropping X) であるため、マージ時に最初に来るようにマージが優先XBれ、2 番目のリストには表示されません。したがって(A, X, object)X

L[KID] = KID + merge((A, X, object), (B, object), (A, B))
#                           ^^^^^^
#                            \removed as it appears in the next list
       = KID + (A, X) + (B, object)
       = (KID, A, X, B, object)
于 2016-09-14T10:43:41.670 に答える