logo

Python でのメソッド解決順序

このチュートリアルでは、MRO とも呼ばれるメソッド解決順序について学びます。これは Python 継承の重要な概念です。

フレームtkinter

メソッド解決順序は、クラスの検索パスを記述します。 パイソン 多重継承を含むクラスで適切なメソッドを取得するために使用します。

導入

ご存知のとおり、継承されるクラスはサブクラスまたは親クラスと呼ばれ、継承されるクラスは子クラスまたはサブクラスと呼ばれます。多重継承では、クラスが多数の関数で構成される可能性があるため、メソッド解決順序手法を使用して、基本クラスが実行される順序を検索します。

簡単に言うと、「メソッドまたは属性は現在のクラスで調査され、メソッドが現在のクラスに存在しない場合は、親クラスに検索が移動します。」ということです。これは深さ優先検索の例です。

これは、同じメソッドが複数のスーパークラスに存在する多重継承において重要な役割を果たします。

これをよりよく理解するために、どのように使用できるかを見てみましょう。

例 -

 class A: def myname(self): print('I am a class A') class B(A): def myname(self): print('I am a class B') class C(A): def myname(self): print('I am a class C') c = C() print(c.myname()) 

出力:

 I am a class C 

説明 -

上記のコードには多重継承があります。 A、B、C という 3 つのクラスを定義しました。これらのクラスにはメソッドという同じ名前が付いています。 自分の名前()。 オブジェクト クラス C を作成しました。オブジェクトはクラスではなくクラス C を呼び出しましたが、クラス C はクラス A のメソッドを継承しました。

上記のコードの順序は次のとおりです。 クラスB - > クラスA。 この手法は、MRO (メソッド解決順序) として知られています。

多重継承の別の例を理解してみましょう。

例 -

 class A: def myname(self): print(' I am a class A') class B(A): def myname(self): print(' I am a class B') class C(A): def myname(self): print('I am a class C') # classes ordering class D(B, C): pass d = D() d.myname() 

出力:

 I am a class B 

説明 -

上記のコードでは、B クラスと C クラスを継承したクラス属性を定義せずに、別の D クラスを作成しました。メソッドを呼び出したとき 自分の名前()、 クラス D に移動し、 自分の名前( ) 関数。しかし、クラス D には宣言がありません。したがって、検索はクラス B に転送され、 自分の名前() 関数を実行し、結果を返します。検索は次のように行われます。

 Class D -> Class B -> Class C -> Class A 

クラス B にメソッドがない場合は、クラス C のメソッドを呼び出します。

ここでは、クラス B メソッドを削除して、何が起こるかを確認することをお勧めします。これを行うと、メソッド解決がどのように機能するかがわかります。

古くて新しいスタイルの注文

Python の古いバージョン (2.1) では、古いクラスの使用に制限されていますが、 パイソン (2.2 & 続き)、新しいクラスを使用できます。デフォルトでは、Python 3 にはオリジナルの (新しい) クラスがあります。新しいスタイル クラスの最初の親は、Python ルートの「オブジェクト」クラスから継承します。次の例を見てみましょう -

タイプスクリプトのアロー関数

例 -

 # Old style class class OldStyleClass: pass # New style class class NewStyleClass(object): pass 

両方のクラスの宣言スタイルは異なります。メソッドの解決では、古いスタイルのクラスは深さ優先の左から右へのアルゴリズム (DLR) に従いますが、新しいスタイルのクラスは多重継承を実行しながら C3 線形化アルゴリズムを使用します。

DLRアルゴリズム

Python は、クラス間の多重継承を実装しながら、クラスのリストを作成します。このリストは、インスタンスによって呼び出されるメソッドを決定するために使用されます。

メソッド解決は深さ優先で検索し、次に左から右に検索するため、その名前から動作すると想定できます。以下にその例を示します。

例 -

 class A: pass class B: pass class C(A, B): pass class D(B, A): pass class E(C,D): pass 

まず、アルゴリズムはインスタンス クラス内で呼び出されたメソッドを検索します。見つからない場合は最初の親に入ります。見つからない場合は最初の親に入ります。親の親を調べます。これはクラスの継承が終了するまで続きます。

Java文字列を連結する

上記の例では、メソッド解決の順序は次のようになります -

 class D -> class B -> class A -> class C -> class A 

ただし、A は 2 回存在することはできないので、-

 class D -> class B -> class A -> class C -> 

このアルゴリズムは当時の奇妙な動作を示しています。以下の例を見てみましょう。

例 -

 class A: pass class B: pass class C(A, B): pass class D(B, A): pass class E(C,D): pass 

DLR アルゴリズムによれば、順序は E、C、D、B、A になります。クラス C にはクラス A と B の交換があり、これは非常に曖昧です。これは、アルゴリズムが単調性の特性を維持しないことを意味します。

Samuele Perdoni は、MRO アルゴリズム間の矛盾を発見した最初の人物です。

C3 線形化アルゴリズム

C3 線形化アルゴリズムは、不一致を取り除くため、DLR アルゴリズムのより優れたバージョンです。このアルゴリズムには、以下に示すいくつかの制限があります。

  • 子供は親に先立たなければなりません。
  • 特定のクラスが 1 つ以上のクラスを継承する場合、それらは基本クラスのタプルで指定された順序で保存されます。

C3 線形化アルゴリズムのルール

  • メソッド解決順序の構造は継承グラフによって定義されます。
  • ユーザーは、ローカル クラスのメソッドにアクセスした後でのみ、スーパー クラスにアクセスする必要があります。
  • 単調性を維持する

メソッド解決クラスのメソッド

Python では、クラスのメソッド解決順序を取得する 2 つの方法が提供されています。 __さん__ 属性または ミスターロ() 方法。これらのメソッドを使用すると、解決されるメソッドの順序を表示できます。

次の例を理解してみましょう。

例 -

 class A: def myname(self): print(' I am a class A') class B(A): def myname(self): print(' I am a class B') class C(A): def myname(self): print('I am a class C') # classes ordering class D(B, C): pass # it prints the lookup order print(D.__mro__) print(C.mro()) 

出力:

 (, , , , ) [, , ] 

上記の出力でわかるように、メソッド解決順序の順序が取得されます。このように、C3 線形化アルゴリズムは多重継承に対して機能します。