python -- MRO C3算法

一、瞭解python2 和python3的區別
 
python2在2.3以前使用的是經典類,2.3以後,使用的是新式類,新式類的特色是基類的根是object
 
python3 中使用的都是新式類,若是基類誰都不繼承,那麼這個類會默認繼承object
 
class Foo:
    pass

class Foo(object):
    pass

  

MRO:method resolution order 方法的查找順序 python

class Base:
    pass

class Base1:
    def eat(self):
        pass
    
class Bar(Base, Base1):
    pass

b = Bar()  # Bar --> Base -->Base1
b.eat()

二、經典類的MRO樹形結構的深度優先遍歷 -->樹形結構遍歷面試

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

畫圖算法

 

結果:Foo-> H -> G -> F -> D -> B -> A -> C -> E.
 
 
三、新式類的MRO  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 G(E):
    pass
class H(G, F):
    pass
⾸先. 咱們要肯定從H開始找. 也就是說. 建立的是H的對象
 
⾸首先. 咱們要肯定從H開始找. 也就是說. 建立的是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          
最後就剩下⼀一個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,
 
驗證
使⽤用類名.__mro__獲取到類的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'>)
 
C3是把咱們多個類產生的共同繼承留到最後去找,因此,咱們也能夠從圖上來看到相關的規律,這個要你們本身多謝多畫圖就能夠感受到。可是若是沒有所謂的共同繼承關係。那幾乎就當成是深度遍歷就能夠了。
 
 
 
 
四、super() 找MRO順序的下一個
 
super()能夠幫咱們執行MRO中下一個父類的方法,一般super()有兩個使用的地方:
 
    一、能夠訪問父類的構造方式
    二、當子類方法想調用父類(MRO)中的方法
 
 
第一種
class Foo:
    def __init__(self,a,b,c):
        self.a = a
        self.b = b
        self.c = c

class Bar(Foo):
    def __init__(self,a,b,c,d):
        super().__init__(a,b,c)  # 訪問父類的構造方法
        self.d = d

b = Bar(1,2,3,4)
print(b.__dict__)

# {'a': 1, 'b': 2, 'c': 3, 'd': 4}
第二種
 
class Foo:
    def func1(self):
        super().func1() # 此時要找的是MRO順序中下一個類的func1()方法
        print("個人老家就住在這個屯")

class Bar:
    def func1(self):
        print("你的老家不在這個屯")

class Ku(Foo,Bar):
    def func1(self):
        super().func1() # 此時super找的是Foo
        print("他的老家不知道在哪一個屯")

k = Ku()  # 先看MRO,Ku,Foo,Bar,object
k.func1()

# 你的老家不在這個屯
# 個人老家就住在這個屯
# 他的老家不知道在哪一個屯
五、一道面試題
 
# MRO + super 面試題
class Init(object):
    def __init__(self, v):
        print("init")
        self.val = v

class Add2(Init):
    def __init__(self, val):
        print("Add2")
        super(Add2, self).__init__(val)
        print(self.val)
        self.val += 2
class Mult(Init):
    def __init__(self, val):
        print("Mult")
        super(Mult, self).__init__(val)
        self.val *= 5

class HaHa(Init):
    def __init__(self, val):
        print("哈哈")
        super(HaHa, self).__init__(val)
        self.val /= 5

class Pro(Add2,Mult,HaHa):
         pass

class Incr(Pro):
    def __init__(self, val):
        super(Incr, self).__init__(val)
        self.val+= 1
# Incr Pro Add2 Mult HaHa Init
p = Incr(5)
print(p.val)
c = Add2(2)
print(c.val)

# Add2
# Mult
# 哈哈
# init
# 5.0
# 8.0
# Add2
# init
# 2
# 4
相關文章
相關標籤/搜索