Python: 多繼承模式下 MRO(Method Resolution Order) 的計算方式

你們可能已經知道了,在 Python 3(Python 2 的新式類)中多繼承模式是使用 C3 算法來肯定 MRO(Method Resolution Order) 的。html

那麼具體是怎麼計算的呢?本文將基於 https://www.python.org/downlo... 中的幾個例子來說解 MRO 是怎麼計算的。python

咱們首先來定義一些符號: :算法

用 CN 表示一個類:C1, C2, C3, ..., CN
C1 C2 C3 ... CN 表示的是一個包含多個類的列表 [C1, C2, C3, ..., CN]

其中: :this

head = C1
tail = C2 ... CN

加法運算: :code

C + (C1 C2 ... CN) = C C1 C2 ... CN
[C] + [C1, C2, ... ,CN] = [C, C1, C2, ..., CN]

L[C] 表示類 C 的線性值,其實就是 C 的 MRO, 其中 :htm

L[object] = object

好比有個類 : :繼承

class C(B1, B2, ..., BN): pass

那麼: :ip

L[C(B1 ... BN)] = C + merge(L[B1] ... L[BN], B1 ... BN)

merge 的計算規則以下:rem

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.文檔

計算 MRO

先從簡單的類提及: :

class B(object): pass

L[B] = L[B(object)]
     = B + merge(L[object])
     = B + L[object]
     = B object

>>> B.mro()
[<class '__main__.B'>, <type 'object'>]

簡單的子類: :

class C(B): pass

L[C] = L[C(B)]
     = C + merge(L[B])
     = C + L[B]
     = C B object     # 從上面已經知道了 L[B] = B object

>>> C.mro()
[<class '__main__.C'>, <class '__main__.B'>, <type 'object'>]

下面來看一個複雜的例子: :

>>> O = object
>>> class F(O): pass
>>> class E(O): pass
>>> class D(O): pass
>>> class C(D,F): pass
>>> class B(D,E): pass
>>> class A(B,C): pass

很容易就能夠想到: :

L[O] = O = object
L[F] = L[F(O)] = F  O
L[E] = L[E(O)] = E  O
L[D] = L[D(O)] = D  O

下面來計算 C, B, A:

L[C]: :

L[C] = L[C(D, F)]
     = C + merge(L[D], L[F], DF)
     # 從前面可知 L[D] 和 L[F] 的結果
     = C +  merge(DO, FO, DF)
     # 由於 D 是順序第一個而且在幾個包含 D 的 list 中是 head,
     # 因此這一次取 D 同時從列表中刪除 D
     = C + D + merge(O, FO, F)
     # 由於 O 雖然是順序第一個但在其餘 list (FO)中不是 head, 跳過,
     # 改成檢查第二個list FO # F 是第二個 list 和其餘 list 的 head, 
     # 取 F同時從列表中刪除 F
     = C + D + F + merge(O)
     = C D F O

>>> C.mro()
[<class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <type 'object'>]

L[B]: :

L[B] = L[B(D, E)]
     = B + merge(L[D], L[E], DE)
     = B + merge(DO, EO, DE)
     = B + D + merge(O, EO, E)
     = B + D + E + merge(O)
     = B D E O

>>> B.mro()
[<class '__main__.B'>, <class '__main__.D'>, <class '__main__.E'>, <type 'object'>]

L[A]: :

L[A] = L[A(B, C)]
     = A + merge(L(B), L(C), BC)
     = A + merge(BDEO, CDFO, BC)
     = A + B + merge(DEO, CDFO, C)
     # 注意這裏是 C , 由於第一個list 的 head D 不是其餘list 的 head
     # 因此改成從下一個 list CDFO 開始
     = A + B + C + merge(DEO, DFO)
     = A + B + C + D + merge(EO, FO)
     = A + B + C  + D + E + merge(O, FO)
     = A + B + C + D + E + F + merge(O)
     = A B C D E F O

>>> A.mro()
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>,
 <class '__main__.D'>, <class '__main__.E'>, <class '__main__.F'>, <type 'object'>]

到這裏應該已經有一點眉目了。下面再來個上面那些類的變種,能夠先本身算算看,後面有詳細的計算過程。

>>> O = object
>>> class F(O): pass
>>> class E(O): pass
>>> class D(O): pass
>>> class C(D,F): pass
>>> class B(E,D): pass
>>> class A(B,C): pass

跟以前惟一的區別是 B(D, E) 變成了 B(E, D) :

L[O] = O = object
L[F(O)] = F  O
L[E(O)] = E  O
L[D(O)] = D  O

L[C] = L[C(D, F)]
     = C + merge(L[D], L[F], DF)
     = C D F O

L[B] = L[B(E, D)]
     = B + merge(L[E], L[D], ED)
     = B + merge(EO, DO, ED)
     = B + E + merge(O, DO, D)
     = B + E + D + merge(O)
     = B E D O
>>> B.mro()
[<class '__main__.B'>, <class '__main__.E'>, <class '__main__.D'>, <type 'object'>]

L[A] = L[A(B, C)]
     = A + merge(L[B], L[C], BC)
     = A + merge(BEDO, CDFO, BC)
     = A + B + merge(EDO, CDFO, C)
     = A + B + E + merge(DO, CDFO, C)
     = A + B + E + C + merge(DO, DFO)
     = A + B + E + C + D + merge(O, FO)
     = A + B + E + C + D + F + merge(O)
     = A B E C D F O
>>> A.mro()
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>,
 <class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <type 'object'>]

經過這幾個例子應該對如何計算 MRO 已經有所瞭解了,更詳細的信息能夠閱讀 python MRO 文檔 以及 wikipedia 中的 C3 算法.

參考資料

原文地址: https://mozillazg.com/2016/11...

相關文章
相關標籤/搜索