參考:https://www.jianshu.com/p/c9a0b055947bpython
類C的線性化記憶爲L[C]=[C1,C2,...Cn],其中C1稱爲L[C]的頭,其他元素[C2,...Cn]稱爲尾。若是一個類C繼承自基類B1,B2,...,B那麼L[C]的計算過程爲blog
#類object爲最高父類,全部類都繼承object L[objicet]=[object] L[C(B1,B2,...Bn)]=[C]+merge(L[B1],L[B2],[B1,B2,...Bn])
merge是將一組列表輸出爲一個列表,其過程爲排序
1,檢查第一個列表的頭元素,記作H 2,若是H是後續序列的第一個元素,或者不在後續序列中再次出現,則將其輸出,並將其從全部列表中刪除,若是不符合跳過此元素,查找下一個列表的第一個元素,而後回到步驟1 3,重複上述步驟,直至列表爲空或者不能再找出能夠輸出的元素。
舉例說明繼承
>>> class A(object): ... pass ... >>> class B(object): ... pass ... >>> class C(A,B): ... pass
首先object,A,B的線性化結果比較簡單get
L[object]=[object] L[A]=[A,object] L[B]=[B,object]
python內置變量__mro__存儲了class
>>> object.__mro__ (<class 'object'>,) >>> A.__mro__ (<class '__main__.A'>, <class 'object'>) >>> B.__mro__ (<class '__main__.B'>, <class 'object'>)
須要計算出L[C]變量
L[C]=[C]+merge(L[A],L[B],[A,B]) =[C]+mergr([A,object],[B,object],[A,B]) #取得的第一個元素是A,是序列[A,B]的第一個元素因此輸出A而且將A從全部列表中刪除 =[C,A]+merge([object],[B,object],[B]) #取得的元素爲object不知足條件,object是序列[B,object]的最後一個元素,跳過取到元素爲B,知足條件,將B輸出並從全部列表刪除B =[C,A,B]+merge([object],[object]) #最後的結果 =[C,A,B,object]
使用__mro__驗證計算結果正確cli
>>> C.__mro__ (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
一個複雜的例子object
class B(object): pass class C(object): pass class D(A,C): pass class E(B,C): pass class F(D,E): pass
計算過程
L[F] = [F] + merge(L[D], L[E], [D, E]) = [F] + merge([D, A, C, object], [E, B, C, object], [D, E]) = [F, D] + merge([A, C, object], [E, B, C, object], [E]) = [F, D, A] + merge([C, object], [E, B, C, object], [E]) = [F, D, A, E] + merge([C, object], [B, C, object]) = [F, D, A, E, B] + merge([C, object], [C, object]) = [F, D, A, E, B, C, object]
驗證計算結果
(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.A'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
以上算法雖然能夠計算出繼承順序,可是不直觀 ,能夠使用圖示拓撲順序進行推導
什麼是拓撲順序
在圖論中,拓撲順序(Topological Storting)是一個有向無環圖(DAG,Directed Acyclic Graph)的全部定點的線性序列。且該序列必須知足一下兩個條件
1,每一個頂點出現且只出現一次
2,若存在一條從頂點A到頂點B的路徑,那麼在序列中頂點A出如今頂點B的前面
看下圖
它是一個DAG圖,那麼若是寫出它的拓撲順序呢?一種比較常見的方法
1,從DAG途中選擇一個沒有前驅(即入度爲0)的頂點並輸出
2,從圖中刪除該頂點和全部以它爲起點的有向邊
3,重複1和2直到當前DAG圖爲空或者當前途中不存在無前驅的頂點爲止。
因而獲得拓撲排序後的結果爲{1,2,4,3,5}
看實例
class A(object): pass class B(object): pass class C1(A,B): pass class C2(A,B): pass class D(C1,C2): pass
根據上述繼承關係構成一張圖
1,找到入度爲0的點,只有一個D,把D拿出來,把D相關的邊減掉
2,如今有兩個入度爲0的點(C1,C2),取最左原則,拿C1,減掉C1相關的邊,這時候的排序是{D,C1}
3, 如今入度爲0的點(C2),拿掉C2,減掉C2相關的邊,這時候的排序是{D,C1,C2}
4,如今入度爲0的點(A,B),取最左原則,拿掉A,減掉A相關的邊,這時候的排序是{D,C1,C2,A}
5,如今入度爲0的點只有B,拿掉B,減掉B相關的邊,最後只剩下object
因此最後的排序是{D,C1,C2,A,B,object}
驗證一下結果
>>> D.__mro__ (<class '__main__.D'>, <class '__main__.C1'>, <class '__main__.C2'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
爲了進一步屬性,在看一個例子
class A(object): pass class B(object): pass class C1(A): pass class C2(B): pass class D(C1,C2): pass
繼承圖
1,找到入度爲0的頂點,只有一個D,拿D,剪掉D相關的邊
2,獲得兩個入度爲0的頂點(C1,C2),根據最左原則,拿C1,剪掉C1相關的邊,這時候序列爲{D,C1}
3,接着看,入度爲0的頂點有兩個(A,C1),根據最左原則,拿A,剪掉A相關的邊,這時候序列爲{D,C1,A}
4,接着看,入度爲0的頂點爲C2,拿C2,剪掉C2相關的邊,這時候序列爲{D,C1,A,C2}
5,繼續,入度爲0的頂點爲B,拿B,剪掉B相關的邊,最後還有一個object
因此最後的序列爲{D,C1,A,C2,B,object}
(<class '__main__.D'>, <class '__main__.C1'>, <class '__main__.A'>, <class '__main__.C2'>, <class '__main__.B'>, <class 'object'>)
使用圖示拓撲法能夠快速計算出繼承順序