Python基礎13_類與型別, MRO, C3演算法, super()
一. python多繼承 類與型別: http://www.cnblogs.com/blackmatrix/p/5594109.html
子類繼承了多個父類, 當父類出現了重名方法時, 這時就涉及到查詢父類方法的問題, 即MRO(method resolution order)問題
python中有兩種類, 經典類和新式類
在Python2及以前的版本中,由任意內建型別派生出的類(只要一個內建型別位於類樹的某個位置),都屬於“新式類”,都會獲得所有“新式類”的特性;反之,即不由任意內建型別派生出的類,則稱之為“經典類”。
“新式類”和“經典類”的區分在Python3之後就已經不存在,在Python3.x之後的版本,因為所有的類都派生自內建型別object(即使沒有顯示的繼承object型別),即所有的類都是“新式類”。
主要是在多重繼承時才會區分二者。
二. 經典類的MRO
經典類的繼承是深度優先遍歷,即從下往上搜索;
所有經典類的程式碼必須在Python2下執行
三. 新式類的MRO 官網C3演算法解釋: https://www.python.org/download/releases/2.3/mro/
新式類的繼承順序是採用C3演算法(非廣度優先, 廣度優先是按層級關係逐層遍歷)
方法中有super()才用得著MRO
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
class E(C, A):
pass
class F(D, E):
pass
class G(E):
pass
class H(G, F):
pass
(1).分拆
首先. 我們要確定從H開始找. 也就是說. 建立的是H的物件.
如果從H找. 那找到H的父類的C3, 我們設C3演算法是L(x) , 即給出x類. 找到x的MRO
L(H) = H + L(G) + L(F) + GF
繼續從程式碼中找G和F的父類往里面帶
L(G) = G + L(E) + E
L(F) = F + L(D)+ L(E) + DE
繼續找E 和 D
L(E) = E + L(C) + L(A) + CA
L(D) = D + L(B) + L(C) + BC
繼續找B和C
L(B) = B + L(A) + A
L(C) = C + L(A) + A
(2).合併
最後就剩下⼀一個A了了. 也就不用再找了了. 接下來. 把L(A) 往里帶. 再推回去. 但要記住. 這里的 + 表示的是merge. merge的原則是用每個元組的頭⼀一項和後面元組的除頭一項外的其他元素進行比較, 看是否存在. 如果存在. 就從下一個元組的頭一項繼續找. 如果找不到. 就拿出來. 作為merge的結果的一項. 以此類推. 直到元組之間的元素都相同. 也就不用再找了了.
L(B) =(B,) + (A,) + (A) -> (B, A)
L(C) =(C,) + (A,) + (A) -> (C, A)
繼續帶.
L(E) = (E,) + (C, A) + (A) + (C,A) -> E, C, A
L(D) = (D,) + (B, A) + (C, A) + (B, C) -> D, B, C, A
繼續帶.
L(G) = (G,) + (E, C, A) + (E) -> G, E, C, A
L(F) = (F,) + (D, B, C, A) + (E, C, A) + (D, E)-> F, D, B, E, C, A
加油, 最後了
L(H) = (H, ) + (G, E, C, A) + ( F, D, B, E, C, A) + (G, F) -> H, G, F, D, B, E, C, A
算完了. 最終結果 HGFDBECA. 那這個算完了. 如何驗證呢? 其實python早就給你準備好了. 我們可以使用類名.__mro__獲取到類的MRO資訊.
print(H.__mro__)
結果:
(<class '__main__.H'>, <class '__main__.G'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>,<class '__main__.A'>, <class 'object'>)
結果OK. 那既然python提供了. 為什麼我們還要如此麻煩的計算MRO呢? 因為筆試.......你在筆試的時候, 是沒有電腦的. 所以這個演算法要知道. 並且簡單的計算要會. 真是項⽬開發的時候很少有人這麼去寫程式碼.
四. super()
super()幫我們執行MRO中下一個父類的方法, 通常super()有兩個使用的地方
1. 可以訪問父類的構造方法, 簡化了子類的書寫
2. 當子類方法想呼叫父類MRO中的方法
super(cls, self).func() 執行cls類的MRO中下一個類的func方法
super().func() 執行當前類的MRO中下一個類的func方法