1. 程式人生 > >day020多繼承,經典類MRO,新式類MRO、C3演算法,super

day020多繼承,經典類MRO,新式類MRO、C3演算法,super

本節內容

1.python多繼承
2.python經典類的MRO
3.python新式類的MRO,C3演算法
4.super()是什麼

一、python多繼承

·當出現了x是⼀種y的的時候. 就可以使⽤繼承關係. 即"is-a" 關係.
·在繼承關係中. ⼦類⾃動擁有⽗類中除了私有屬性外的其他所有內容. python⽀持多繼承.
·⼀個類可以擁有多個⽗類.
·一個父類也可以有多個子類

1、兩種類

經典類(python2,僅在面試會有)

·在python2.2之前. 已經是歷史了.
·MRO 採用的是樹形結構的深度遍歷(一條道跑到黑)
·經典類在基類的根如果什麼都不寫. 表⽰繼承xxx.

新式類(python3,現在所使用的)

·在2.2之後產生新式類.  目前我們使用的. 所有的類的根都是object C3演算法(merge)
·如果基類誰都不繼承. 那這個類會預設繼承object

fe:新式類的示例

class Shen:
    def fly(self): print("大神會飛") class Hou: def chi(self): print("猴子吃桃子") class SunWuKong(Shen, Hou): # 一個類可以繼承多個無關的類. 一個類可以被多個無關的類繼承 pass class TaiShangLaoJun(Shen): pass # # swk = SunWuKong() # swk.fly() # swk.chi()

二、經典類的MRO

學一學,這是一種樹形結構遍歷的一個最直接案例。

fe:已經沒有機器跑2.0了,只能說明原理,手動求解

class A:
    pass

class B(A):
    pass

class C(A):
    pass

class D(B, C):
    pass

class E:
    pass

class F(D, E):
    pass

class G(F, D):
     pass

class H:
    pass

class Foo(H, G):
    pass
類的MRO: Foo-> H -> G -> F -> D -> B -> A -> C -> E

1、深度優先和廣度優先


如圖. 肯定是按照123456這樣的順序來送. 那這樣的順序就叫深度優先遍歷.
⽽如果是142356呢? 這種被稱為⼴度優先遍歷.
好了. 深度優先就說這麼多. 那麼上⾯那個圖怎麼呢?
MRO是什麼呢?
很簡單. 記住. 從頭開始. 從左往右. ⼀條路跑到頭, 然後回頭. 繼續⼀條路跑到頭.
就是經典類的MRO演算法.

三、新式類的MRO(要會算,給面試官用的,實戰上會呼叫就行)

python中的新式類的MRO是採⽤的C3演算法來完成的.

fe:C3演算法

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 M(F, E): pass class N: pass class P(M,N): pass class G(P): pass class O: pass class X(O): pass class H(G, X, F): pass print(H.__mro__) ''' # 計算過程 L(H) = H + L(G) + L(X) + L(F) + GXF HGPMXFDBECANO L(G) = G + L(P) + P # GPMFDBECAN L(X) = X + L(O) + O # XO L(F) = F + L(D) + L(E) + DE # FDBECA L(P) = P + L(M) + L(N) + MN # PMFDBECAN L(D) = D + L(B) + L(C) + BC # DBCA L(E) = E + L(C) + L(A) + CA # ECA L(M) = M + L(F) + L(E) + FE # ECA ECA E MFDBECA '''

1、C3演算法的關鍵:merge原則

最後就剩下⼀個A了. 也就不⽤再找了. 接下來. 把L(A) 往⾥帶. 再推回去.
但要記住. 這⾥的+ 表⽰的是merge.
*merge的原則:是⽤每個元組的頭⼀項和後⾯所有元組的除頭⼀項外的其他元素進⾏比較, *
1.看是否存在. 如果存在. 就從下⼀個元組的頭⼀項繼續找. 下一組找到之後返回頭一項,
2.如果找不到. 就拿出來.作為merge的結果的⼀項. 以此類推. 直到元組之間的元素都相同. 也就不⽤再找了.

2、為什麼要會算,因為面試

結果OK. 那既然python提供了. 為什麼我們還要如此⿇煩的計算MRO呢?
 因為筆試.......你在筆試的時候, 是沒有電腦的. 所以這個演算法要知道.
 並且簡單的計算要會. 真是項⽬開發的時候很少有⼈這麼去寫程式碼.

四、super是什麼

super()可以幫我們執⾏MRO中下⼀個⽗類的⽅法. 通常super()有兩個使⽤的地⽅:
1. 可以訪問⽗類的構造⽅法
2. 當⼦類⽅法想調⽤⽗類(MRO)中的⽅法

fe1: 訪問父類的構造方法

# super是查詢mro順序中的下一個
# 單繼承中我們可以認為super是對父類中的屬性或方法的引入

class ShengWu: def dong(self): # 例項方法 print(self) print("我是生物") class Animal(ShengWu): pass class Cat(Animal): def dong(self): # 子類中出現了和父類重名的內容. 表示對父類的方法的覆蓋(重寫). 半蓋(java) super(Animal, self).dong() # 定位到Animal. 找Animal的下一個 # super().dong() # 預設呼叫上一個父類的,常用 # super(類, 物件).方法() 找到MRO中的類. 找這個類的下一個. 去執行方法 print("我的貓也會動") # 找MRO中的下一個 # Cat -> Animal -> ShengWu c = Cat() print(c) c.dong()

fe2: ⼦類⽅法想調⽤⽗類(MRO)中的⽅法

class Foo:
    def func1(self): super().func1() # 此時找的是MRO順序中下⼀個類的func1()⽅法 print("我的⽼家. 就住在這個屯") class Bar: def func1(self): print("你的⽼家. 不在這個屯") class Ku(Bar, FOO): def func1(self): super().func1() # 此時super找的是Foo print("他的⽼家. 不知道在哪個屯") k = Ku() # 先看MRO . KU, FOO, BAR object k.func1() k2 = Foo() # 此時的MRO. Foo object k2.func1() # 報錯

面試題:MRO + super

# MRO + super ⾯試題
class Init(object): def __init__(self, v): print("init") self.val = v # 2 class Add2(Init): def __init__(self, val): # 2 print("Add2") super(Add2, self).__init__(val) print(self.val) # 5.0 self.val += 2 # 7.0 class Mult(Init): def __init__(self, val): print("Mult") super(Mult, self).__init__(val) self.val *= 5 # 5.0 class HaHa(Init): def __init__(self, val): print("哈哈") super(HaHa, self).__init__(val) self.val /= 5 # 1.0 class Pro(Add2,Mult,HaHa): # pass class Incr(Pro): def __init__(self, val): # 5 super(Incr, self).__init__(val) self.val += 1 # 8.0 # Incr, pro, add2, mult, haha, Init p = Incr(5) print(p.val) # ? # Add2 init c = Add2(2) print(c.val) # ?

提⽰. 先算MRO . 然後看清楚self是誰.

結論: 不管super()寫在哪⼉. 在哪⼉執⾏. ⼀定先找到MRO列表. 根據MRO列表的順序往下找. 否則⼀切都是錯的