多繼承
class ShenXian: # 神仙
def fei(self):
print("神仙都會⻜")
class Monkey: # 猴
def chitao(self):
print("猴⼦喜歡吃桃⼦")
class SunWukong(ShenXian, Monkey): # 孫悟空是神仙, 同時也是⼀只猴
pass
sxz = SunWukong() # 孫悟空
sxz.chitao() # 會吃桃⼦
sxz.fei() # 會⻜
此時, 孫悟空是⼀只猴⼦, 同時也是⼀個神仙. 那孫悟空繼承了這兩個類. 孫悟空⾃然就可以執⾏這兩個類中的⽅法. 多繼承⽤起來簡單. 也很好理解. 但是多繼承中, 存在着這樣⼀個問題. 當兩個⽗類中出現了重名⽅法的時候. 這時該怎么辦呢? 這時就涉及到如何查找⽗類⽅法的這么⼀個問題.即MRO(method resolution order) 問題. 在python中這是⼀個很復雜的問題. 因為在不同的python版本中使⽤的是不同的算法來完成MRO的.
這里需要補充一下python中類的種類(繼承需要):
在python2x版本中存在兩種類.:
⼀個叫經典類. 在python2.2之前. ⼀直使⽤的是經典類. 經典類在基類的根如果什么都不寫.
⼀個叫新式類. 在python2.2之后出現了新式類. 新式類的特點是基類的根是object類。
python3x版本中只有一種類:
python3中使⽤的都是新式類. 如果基類誰都不繼承. 那這個類會默認繼承 object
1經典類的多繼承
雖然在python3中已經不存在經典類了. 但是經典類的MRO最好還是學⼀學. 這是⼀種樹形結構遍歷的⼀個最直接的案例. 在python的繼承體系中. 我們可以把類與類繼承關系化成⼀個樹形結構的圖. 來, 上代碼:
代碼示例
對付這種mro畫圖就可以:

繼承關系圖已經有了. 那如何進⾏查找呢? 記住⼀個原則. 在經典類中采⽤的是深度優先,遍歷⽅案. 什么是深度優先. 就是⼀條路走到頭. 然后再回來. 繼續找下⼀個.

圖中每個圈都是准備要送雞蛋的住址. 箭頭和⿊線表⽰線路. 那送雞蛋的順序告訴你入⼝在最下⾯R. 並且必須從左往右送. 那怎么送呢?

如圖. 肯定是按照123456這樣的順序來送. 那這樣的順序就叫深度優先遍歷. ⽽如果是142356呢? 這種被稱為⼴度優先遍歷. 好了. 深度優先就說這么多. 那么上⾯那個圖怎么找的呢? MRO是什么呢? 很簡單. 記住. 從頭開始. 從左往右. ⼀條路跑到頭, 然后回頭. 繼續⼀條路跑到頭. 就是經典類的MRO算法.
類的MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C. 你猜對了么?
2新式類的多繼承
2.1 mro序列
MRO是一個有序列表L,在類被創建時就計算出來。
通用計算公式為:
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
(其中Child繼承自Base1, Base2)
如果繼承至一個基類:class B(A)
這時B的mro序列為
mro( B ) = mro( B(A) ) = [B] + merge( mro(A) + [A] ) = [B] + merge( [A] + [A] ) = [B,A]
如果繼承至多個基類:class B(A1, A2, A3 …)
這時B的mro序列
mro(B) = mro( B(A1, A2, A3 …) ) = [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] ) = ...
計算結果為列表,列表中至少有一個元素即類自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。
2.2. 表頭和表尾
表頭:
列表的第一個元素
表尾:
列表中表頭以外的元素集合(可以為空)
示例
列表:[A, B, C]
表頭是A,表尾是B和C
2.3. 列表之間的+操作
+操作:
[A] + [B] = [A, B]
(以下的計算中默認省略)
---------------------
merge操作示例:
如計算merge( [E,O], [C,E,F,O], [C] ) 有三個列表 : ① ② ③ 1 merge不為空,取出第一個列表列表①的表頭E,進行判斷 各個列表的表尾分別是[O], [E,F,O],E在這些表尾的集合中,因而跳過當前當前列表 2 取出列表②的表頭C,進行判斷 C不在各個列表的集合中,因而將C拿出到merge外,並從所有表頭刪除 merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] ) 3 進行下一次新的merge操作 ...... ---------------------

計算mro(A)方式:
mro(A) = mro( A(B,C) )
原式= [A] + merge( mro(B),mro(C),[B,C] )
mro(B) = mro( B(D,E) )
= [B] + merge( mro(D), mro(E), [D,E] ) # 多繼承
= [B] + merge( [D,O] , [E,O] , [D,E] ) # 單繼承mro(D(O))=[D,O]
= [B,D] + merge( [O] , [E,O] , [E] ) # 拿出並刪除D
= [B,D,E] + merge([O] , [O])
= [B,D,E,O]
mro(C) = mro( C(E,F) )
= [C] + merge( mro(E), mro(F), [E,F] )
= [C] + merge( [E,O] , [F,O] , [E,F] )
= [C,E] + merge( [O] , [F,O] , [F] ) # 跳過O,拿出並刪除
= [C,E,F] + merge([O] , [O])
= [C,E,F,O]
原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
= [A,B] + merge( [D,E,O], [C,E,F,O], [C])
= [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳過E
= [A,B,D,C] + merge([E,O], [E,F,O])
= [A,B,D,C,E] + merge([O], [F,O]) # 跳過O
= [A,B,D,C,E,F] + merge([O], [O])
= [A,B,D,C,E,F,O]
---------------------
結果OK. 那既然python提供了. 為什么我們還要如此⿇煩的計算MRO呢? 因為筆
試.......你在筆試的時候, 是沒有電腦的. 所以這個算法要知道. 並且簡單的計算要會. 真是項⽬
開發的時候很少有⼈這么去寫代碼.
這個說完了. 那C3到底怎么看更容易呢? 其實很簡單. C3是把我們多個類產⽣的共同繼
承留到最后去找. 所以. 我們也可以從圖上來看到相關的規律. 這個要⼤家⾃⼰多寫多畫圖就
能感覺到了. 但是如果沒有所謂的共同繼承關系. 那⼏乎就當成是深度遍歷就可以了

