1. ホーム
  2. python

[解決済み] 新スタイルのクラスにおけるMRO(Method Resolution Order)とは?

2022-12-29 08:08:37

質問

本の中で Python in a Nutshell (第2版) を使用した例があります。

古いスタイルのクラスを使って、どのようにメソッドが古典的な解決順序で解決されるかを示す例と

新しい順序でどのように異なるかを示します。

同じ例を新しいスタイルに書き換えて試してみましたが、結果は古いスタイルのクラスで得られたものと変わりません。この例を実行するために使用している Python のバージョンは次のとおりです。 2.5.2. 以下はその例です。

class Base1(object):  
    def amethod(self): print "Base1"  

class Base2(Base1):  
    pass

class Base3(object):  
    def amethod(self): print "Base3"

class Derived(Base2,Base3):  
    pass

instance = Derived()  
instance.amethod()  
print Derived.__mro__  

呼び出し instance.amethod() が印刷されます。 Base1 と表示されますが、新しいスタイルのクラスを持つMROの私の理解では、出力は次のようになるはずです。 Base3 . 呼び出しは Derived.__mro__ をプリントします。

(<class '__main__.Derived'>, <class '__main__.Base2'>, <class '__main__.Base1'>, <class '__main__.Base3'>, <type 'object'>)

新しいスタイルクラスを持つMROの私の理解は間違っているのか、それとも私が発見できない愚かな間違いを犯しているのか、よくわかりません。MRO をよりよく理解するために、私を助けてください。

どのように解決するのですか?

レガシー クラスと新スタイル クラスの解決順序の決定的な違いは、quot;naive" の深さ優先のアプローチで同じ祖先クラスが複数回出現する場合に生じます -- 例: ダイヤモンド継承の場合を考えてみてください。

>>> class A: x = 'a'
... 
>>> class B(A): pass
... 
>>> class C(A): x = 'c'
... 
>>> class D(B, C): pass
... 
>>> D.x
'a'

ここで、レガシースタイルでは、解決順序は D - B - A - C - A : なので、D.x を調べるとき、A は解決順序の最初の拠点となり、それによって C に定義が隠されていることになります。

>>> class A(object): x = 'a'
... 
>>> class B(A): pass
... 
>>> class C(A): x = 'c'
... 
>>> class D(B, C): pass
... 
>>> D.x
'c'
>>> 

ここで、ニュースタイルでは、順番は

>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, 
    <class '__main__.A'>, <type 'object'>)

A は一度だけ、そのサブクラスのすべての後に解決順序で来ることを強制されるので、オーバーライド (すなわち、C によるメンバー x の C のオーバーライド) が実際に賢明に機能するようにします。

これは、旧式のクラスが避けられるべき理由の一つです。quot;ダイヤモンドライク"パターンによる多重継承は、新式のクラスではうまくいきますが、旧式のクラスでは感覚的にうまくいかないのです。