Python-Beyond the Basics--Inheritance & Subtype Polymorphism

5618 ワード

最近pluralsightのpython-beyond the basicsチュートリアルを見て、たくさんのことを学びました.ここで覚えておきます.
この節では、継承に関する知識について説明します.
Method Resolution Order
1.定義
MROは、継承において、クラス自体とベースクラスに同じ名前の関数定義が複数ある場合に、最終的な知的行の関数をどのように検索すべきかを示します.それ自体はordering of the inheritance graphです.
2.表示
YOUR_CLASS.__mro__ もしくはYOUR_CLASS.mro()
違いは_mro__発生したのはtupleで、mro()は配列です
任意のclassのmroの最後の要素はobject classです
例:
class A(object):
    def func(self):
        return 'A.func'

class B(A):
    def func(self):
        return 'B.func'

class C(A):
    def func(self):
        return 'C.func'

class D(C, B):
    pass
    
print D.mro()

結果は次のとおりです.
[, , , , ]

注意:python 2.7.8で、class A定義時にobjectが継承されていないことが判明した場合、classのmroを表示するとエラーが報告されます.
3.使用
対obj.method()呼び出しでは、pythonはclassのMROリストのclassでclassに一致する関数があるかどうかを順番に検索します.
見つかったら、classに対応する関数を呼び出して実行します.
したがって、上記のclass Dについて実行すると、次のようになります.
d = D()
d.func()

次のようになります.
'C.func'

Dの継承順序を変更する、B,Cの位置を交換すると、実行結果は"B.func"となる.
4.計算
C 3--pythonでMROを計算するアルゴリズム、参考URL:The Python 2.3 Method Resolution Order and C 3
C3 makes sure:
1)subclass base classより前
    2) base class from class definition is preserved
    3) First two qualities are preserved no matter where you stat in the inheritance graph.
よく分からないようです.最初のリンクから計算方法を示します.
マルチ継承構造におけるクラスCにとって、CのベースクラスはB 1,B 2,…である.Bn. クラスCの線形値(Linearization)L[C]を計算するには、次のようにします.
L[C]は、Cに親の線形値と親リストを加えたmergeの結果であり、式は以下の通りである.
L[C (B1, B2, ...Bn)] = C +merge (L[B1], L[B2],.....  L[Bn],  B1,  B2, ....., Bn)
特に、L[object]=object. 
mergeの核心的な説明は:
take the head of the first list, i.e L[B1][0]; if this head is not in the tail of any of the other lists, then add it to the linearization of C and remove it from the lists in the merge, otherwise look at the head of the next list and take it, if it is a good head. Then repeat the operation until all the class are removed or it is impossible to find good heads. In this case, it is impossible to construct the merge, Python 2.3 will refuse to create the class C and will raise an exception.
ベースクラスBが1つしかないクラスCの場合,L[C(B)]=C+merge(L[B],B)=C+L[B]である.
文章:Python MRO C 3は詳細な解析を与えた.
具体的な実装コードはgithubにある:functools.py関数:c3_merge .
def _c3_merge(sequences):
    """Merges MROs in *sequences* to a single MRO using the C3 algorithm.
    Adapted from http://www.python.org/download/releases/2.3/mro/.
    """
    result = []
    while True:
        sequences = [s for s in sequences if s]   # purge empty sequences
        if not sequences:
            return result
        for s1 in sequences:   # find merge candidates among seq heads
            candidate = s1[0]
            for s2 in sequences:
                if candidate in s2[1:]:
                    candidate = None
                    break      # reject the current head, it appears later
            else:
                break
        if candidate is None:
            raise RuntimeError("Inconsistent hierarchy")
        result.append(candidate)
        # remove the chosen candidate
        for seq in sequences:
            if seq[0] == candidate:
                del seq[0]

文章:Python MRO C 3は「動作的には両端をつまんでまっすぐにする.(各ノード間のロープは最大の弾力性を持ち、まっすぐにすることを保証し、最小は2つのノードのマルチパスの下の最大ステップ長である)」とまとめているが、やはりイメージ的だ.
5.応用
"The  __mro__  attribute of the type lists the method resolution search order used by both  getattr()  and  super() ."
つまりgetattrとsuperはMROを利用してmethodを検索します
Built-In Super Function
1.定義
MROを理解した上で、superを見ると簡単です.
“Given a method resolution order and a class C,super() gives you a object which resolves methods using only the part of the MRO which comes after C”.
super()は、method呼び出しをルーティングするために使用されるproxyオブジェクトを返します.
def super(type, object_or_type):
     pass
2.パラメータの説明:
2番目のパラメータが無視されている場合、superの呼び出しはunboundオブジェクトを返します.この場合はごくわずかですが、pluralsightでは直接スキップしましたが、この使い方を分析している人がいるのを見て、Pythonで精神分裂させたsuper classを参考にすることができます.
2番目のパラメータが指定されるとbound proxyと呼ばれ、これは一般的です.
bound proxyには、次の2つのタイプがあります.
1) instance-bound:
super(class,instance-of-class)は、instanceがclassのインスタンス(isinstance(instance,class)=true)であることを要求する.
superを呼び出すと、次のようになります.
  • は、2番目のパラメータのタイプに対応するMRO
  • を取得する
  • MROにおける最初のパラメータclassの位置
  • を見つける
  • は次に、method
  • を解析するために、MROの後にあるclassのすべてのclassを使用する.
    2) class-bound: 
    super(base-class,derived-class)は、derived-classがbase-classのサブクラス(より正確にはissubclass(derived-class,base-class)=true)であることを要求します.そうしないと、異常を放出します.
    super class bound proxyを呼び出すと、次のようになります.
  • python derived classのMRO
  • を入手
  • MROでbase class
  • を見つけます
  • その後、base classの後ろにあるすべてのclassから、最初に一致する関数のクラスが見つかります.

  • 一致するクラスを検索するときは、base classの後ろから始まり、base class自体は含まれません.
    3.パラメータのないsuper()
    python 3.xにはパラメータなしsuper()関数が追加され、呼び出しコンテキストに関係することを意味します.
    1)instance methodではsuper(class-of-method,self)に等しい
    2)class methodではsuper(class-of-method,class)に等しい