Python3多重繼承排序原理(C3演算法)

2022-06-24 09:36:11 字數 3651 閱讀 6093

參考:

類c的線性化記憶為l[c]=[c1,c2,...cn],其中c1稱為l[c]的頭,其餘元素[c2,...cn]稱為尾。如果乙個類c繼承自基類b1,b2,...,b那麼l[c]的計算過程為

#類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的線性化結果比較簡單

l[object]=[object]

l[a]=[a,object]

l[b]=[b,object]

python內建變數__mro__儲存了

>>> object.__mro__

(,)>>> a.__mro__

(, )

>>> b.__mro__

(, )

需要計算出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__驗證計算結果正確

>>> c.__mro__

(, , , )

乙個複雜的例子

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]

驗證計算結果

(, , , , , , )
以上演算法雖然可以計算出繼承順序,但是不直觀 ,可以使用圖示拓撲順序進行推導

什麼是拓撲順序

在圖論中,拓撲順序(topological storting)是乙個有向無環圖(dag,directed acyclic graph)的所有定點的線性序列。且該序列必須滿足一下兩個條件

1,每個頂點出現且只出現一次

2,若存在一條從頂點a到頂點b的路徑,那麼在序列中頂點a出現在頂點b的前面

看下圖

它是乙個dag圖,那麼如果寫出它的拓撲順序呢?一種比較常見的方法

1,從dag途中選擇乙個沒有前驅(即入度為0)的頂點並輸出

2,從圖中刪除該頂點和所有以它為起點的有向邊

3,重複1和2直到當前dag圖為空或者當前途中不存在無前驅的頂點為止。

於是得到拓撲排序後的結果為

看例項

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相關的邊,這時候的排序是

3, 現在入度為0的點(c2),拿掉c2,減掉c2相關的邊,這時候的排序是

4,現在入度為0的點(a,b),取最左原則,拿掉a,減掉a相關的邊,這時候的排序是

5,現在入度為0的點只有b,拿掉b,減掉b相關的邊,最後只剩下object

所以最後的排序是

驗證一下結果

>>> d.__mro__

(, , , , , )

為了進一步屬性,在看乙個例子

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相關的邊,這時候序列為

3,接著看,入度為0的頂點有兩個(a,c1),根據最左原則,拿a,剪掉a相關的邊,這時候序列為

4,接著看,入度為0的頂點為c2,拿c2,剪掉c2相關的邊,這時候序列為

5,繼續,入度為0的頂點為b,拿b,剪掉b相關的邊,最後還有乙個object

所以最後的序列為

(, , , , , )
使用圖示拓撲法可以快速計算出繼承順序

python3中多重繼承的問題

本來以為多重繼承很簡單,但是多看了一些資料後發現還是挺複雜的。如果繼承情況簡單就還比較好理解,但是如果繼承的情況太過於複雜的話,python3 中會使用拓撲排序的方式來尋找繼承的父類。有關繼承的拓撲排序 關於這方面看上面的文章就可以了。我下面給出除此之外的一些說明 class a object de...

python 多重繼承之拓撲排序

在圖論中,拓撲排序 topological sorting 是乙個有向無環圖 dag,directed acyclic graph 的所有頂點的線性序列。且該序列必須滿足下面兩個條件 例如,下面這個圖 它是乙個dag圖,那麼如何寫出它的拓撲順序呢?這裡說一種比較常用的方法 於是,得到拓撲排序後的結果...

python 多重繼承之拓撲排序

在圖論中,拓撲排序 topological sorting 是乙個有向無環圖 dag,directed acyclic graph 的所有頂點的線性序列。且該序列必須滿足下面兩個條件 例如,下面這個圖 它是乙個dag圖,那麼如何寫出它的拓撲順序呢?這裡說一種比較常用的方法 於是,得到拓撲排序後的結果...