在 Python 中用到多繼承時,調用父類方法很容易出錯:父類方法調用了多次,只能通過__mro__
魔法方法來獲取調用順序,花了點時間了解其中涉及的排序算法,順帶記錄
1. 拓撲排序
在了解 MRO 排序算法之前,先了解下拓撲排序(以下摘自維基百科)
在圖論中,由一個有向無環圖的頂點組成的序列,當且僅當滿足下列條件時,稱為該圖的一個拓撲排序(英語:Topological sorting)。
1.每個頂點出現且只出現一次;
2.若A在序列中排在B的前面,則在圖中不存在從B到A的路徑。
說人話,看下面的圖就明白了 (圖片搬運自別人的博客,畫的很不錯我直接拿來用了,鏈接在文章末尾),圖中每個點都是有指向性的:可能指向別人或者被別人指向。
拓撲順序就是:每次找到一個只指向別人的點 (學術性說法:入度為0),記錄下來;然后忽略掉這個點和它所指出去的線,再找到下一個只指向別人的點,記錄下來,直到剩最后一個點,所有記錄的點的順序就是拓撲順序
上圖中,只有點1
只指向別人,輸出1;去掉點1
和它伸出的兩根線外只有點2
只指向別人,輸出2;...類推下去,得到拓撲排序結構: 1 2 4 3 5
2. MRO 排序算法
- MRO 排序應用了 C3 算法,想了解 C3 自己查吧...總之得到的結果類似于拓撲排序,下面有段簡單的多繼承代碼和其對應的拓撲排序的抽象圖 (所用代碼實例和圖片均來應用自別處,文章末尾有鏈接)
class D(object):
pass
class E(object):
pass
class F(object):
pass
class C(D, F):
pass
class B(E, D):
pass
class A(B, C):
pass
if __name__ == '__main__':
print A.__mro__
得到的輸出結果:
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <type 'object'>)
-
下面就是抽象出來的圖
我們就用拓撲排序來分析,但是這里會碰到同時存在好幾個點都是入度為0 (說人話,就是沒有被別人指向的點),這時按照樹的排序來,即從左到右,從根到葉,這里 A 就是根。
所以具體情況就是:我們先找到了點 A只有它沒有被別人指向,輸出A
;去掉A及其伸出的兩條線,剩 B 和 C 點同時滿足只指向別人,按照樹的順序從左到右,故先輸出B
;去掉線剩 E 和 C ,輸出E
;去線剩 C,輸出C
;去線剩 D 和 F ,輸出D
;去線只剩F ,輸出F
;最后輸出object
;得到的輸出結果:
A B E C D F object
對比系統打印出的結果,順序是一致的。這樣下次你就可以裝逼地手動計算多繼承時調用類的順序了 (好像沒啥卵用~)
引用文章: