9

Python で、同じメソッドで 2 つのクラスを定義し、それら 2 つのクラスを親クラスにする場合は、次のようになります。

class A(object):
     def hello(self):
         print "hello from class a" 

と:

class B(object):
     def hello(self):
         print "hello from class b"

子クラスを定義し、A と B の順序で 2 つの親クラスを追加すると、次のようになります。

class C(A, B):
     def __init__(self):
         self.hello()

self.method() を呼び出すときに使用されるメソッドは、A に属するメソッド、または継承リストの最初のクラスです。

>>> C()
hello from class a
<__main__.C object at 0x10571e9d0>

これは私のすべてのテストケースに当てはまりますが、ドキュメントやオンラインで、どのプラットフォームや言語の実装でも実際に安全であるという場所を見つけることができません。リスト内の最初に継承されたクラスが常に他のクラスよりも使用されるメソッドであると仮定しても安全であることを誰でも確認できますか (super().__init__() 呼び出しなどに関係なく)、またはこれを確認する公式ドキュメントを参照してください。

ありがとうございました、

4

2 に答える 2

12

はい、メソッド解決順序 ( C3 線形化)を計算するための新しいアルゴリズムを導入したドキュメントで説明されているように保証されています。

このアルゴリズムを使用しない実装は、mro実際には Python 言語 (バージョン 2.3+) に準拠していません。私の知る限り、現在の実装はすべてC3線形化を使用しています。


C3 線形化は、局所的な優先順位と単調性のプロパティを満たします。ローカル優先順位とは、クラスが継承リストにリストされた順序で基本クラスC(B1, ..., Bn)を持つことを意味します。mroBi

単調性は、おそらく次の例でよりよく説明されます。

>>> class A(object): pass
>>> class B(object): pass
>>> class C(object): pass
>>> class D(object): pass
>>> class E(object): pass
>>> class K1(A,B,C): pass
>>> class K2(D,B,E): pass
>>> class K3(D,A):   pass
>>> class Z(K1,K2,K3): pass

python2.2 の古い mro (これは単調ではありません)。これらは上記のクラスの線形化です。

L[A] = A O
L[B] = B O
L[C] = C O
L[D] = D O
L[E] = E O
L[K1]= K1 A B C O
L[K2]= K2 D B E O
L[K3]= K3 D A O
L[Z] = Z K1 K3 A K2 D B C E O
# in current versions of python (2.3+):
# L[Z] = Z K1 K2 K3 D A B C E O

ここで、 の線形化ではクラスが の前に来るのZに対し、クラスの線形化では のに来ることがわかります。単調性は線形化の特性であり、継承時にこの種のスワップはありません。クラスがクラスの親のすべての線形化でクラスに先行する場合、最終的な線形化でもクラスに先行します。ADK3 DXYY

さて、クラスを考えてみC(B1, ..., Bn)ます。ローカル優先順位により、クラスB1, ..., Bnは の線形化でその順序で検出されCます。Bi単調性により、s 自体の前に s のサブクラスを見つけることはできませんBi。このことから、 の線形化が存在する場合、とCで開始する必要があることがわかります。CB1

場合によっては、線形化を計算できないことに注意してください。Python は次のように文句を言います。

>>> class A(object):pass
... 
>>> class B(object, A): pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Cannot create a consistent method resolution
order (MRO) for bases object, A

ただし、クラスを交換すると、階層を線形化することができます。

>>> class B(A, object): pass
... 
>>> B.mro()
[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

親クラスに共通のベースがない場合 (object明らかにそれ以外)、 の線形化が( を除く)C(B1, ..., Bn)の線形化で始まり、etcの線形化が続き、 の線形化で終わることは明らかです。B1objectB2Bn

>>> class A(object): pass
... 
>>> class B(object): pass
... 
>>> class A1(A): pass
... 
>>> class A2(A1): pass
... 
>>> class B1(B): pass
... 
>>> class C(object): pass
... 
>>> class C1(C): pass
... 
>>> class C2(C1):pass
... 
>>> class C3(C2): pass
... 
>>> class D(A2, B1, C3): pass
... 
>>> D.mro()
[<class '__main__.D'>, <class '__main__.A2'>, <class '__main__.A1'>, <class '__main__.A'>, <class '__main__.B1'>, <class '__main__.B'>, <class '__main__.C3'>, <class '__main__.C2'>, <class '__main__.C1'>, <class '__main__.C'>, <class 'object'>]

s の間にいくつかの共通のサブクラスがあると、事態は奇妙になり始めますBi。この場合、python は、ローカルの優先順位と単調性に違反しないと予想される順序を見つけるか、エラーが発生します。

于 2014-02-09T12:51:01.130 に答える