Python 多重繼承 mro

2021-06-21 09:14:37 字數 3222 閱讀 6376

mro即

method resolution order

,主要用於在多繼承時判斷調的屬性的路徑(來自於哪個類)。之前檢視了很多資料,說mro是基於深度優先搜尋演算法的。但不完全正確在python2.3之前是基於此演算法,但從python2.3起應用了新演算法:c3演算法。

為什麼採用c3演算法

c3演算法最早被提出是用於lisp的,應用在python中是為了解決原來基於深度優先搜尋演算法不滿足本地優先順序,和單調性的問題。

本地優先順序:指宣告時父類的順序,比如c(a,b),如果訪問c類物件屬性時,應該根據宣告順序,優先查詢a類,然後再查詢b類。

單調性:如果在c的解析順序中,a排在b的前面,那麼在c的所有子類裡,也必須滿足這個順序。

在python官網的the python 2.3 method resolution order中作者舉了例子,說明這一情況。

f=type('food', (), )

e=type('eggs', (f,), )

g=type('goodfood', (f,e), {})

根據本地優先順序在呼叫g類物件屬性時應該優先查詢f類,而在python2.3之前的演算法給出的順序是g e f o,而在心得c3演算法中通過阻止類層次不清晰的宣告來解決這一問題,以上宣告在c3演算法中就是非法的。

c3演算法

判斷mro要先確定乙個線性序列,然後查詢路徑由由序列中類的順序決定。所以c3演算法就是生成乙個線性序列。

如果繼承至乙個基類:

class b(a)

這時b的mro序列為[b,a]

如果繼承至多個基類

class b(a1,a2,a3 ...)

這時b的mro序列 mro(b) = [b] + merge(mro(a1), mro(a2), mro(a3) ..., [a1,a2,a3])

merge操作就是c3演算法的核心。

遍歷執行merge操作的序列,如果乙個序列的第乙個元素,在其他序列中也是第乙個元素,或不在其他序列出現,則從所有執行merge操作序列中刪除這個元素,合併到當前的mro中。

merge操作後的序列,繼續執行merge操作,直到merge操作的序列為空。

如果merge操作的序列無法為空,則說明不合法。

例子:class a(o):pass

class b(o):pass

class c(o):pass

class e(a,b):pass

class f(b,c):pass

class g(e,f):pass

a、b、c都繼承至乙個基類,所以mro序列依次為[a,o]、[b,o]、[c,o]

mro(e) = [e] + merge(mro(a), mro(b), [a,b])

= [e] + merge([a,o], [b,o], [a,b])

執行merge操作的序列為[a,o]、[b,o]、[a,b]

a是序列[a,o]中的第乙個元素,在序列[b,o]中不出現,在序列[a,b]中也是第乙個元素,所以從

執行merge操作的序列(

[a,o]、[b,o]、[a,b]

)中刪除a,合併到當前mro,[e]中。

mro(e) = [e,a] + merge([o], [b,o], [b])

mro(e) = [e,a,b] + merge([o], [o])

= [e,a,b,o] 同理

mro(f) = [f] + merge(mro(b), mro(c), [b,c])

= [f] + merge([b,o], [c,o], [b,c])

= [f,b] + merge([o], [c,o], [c])

= [f,b,c] + merge([o], [o])

= [f,b,c,o]

mro(g) = [g] + merge(mro[e], mro[f], [e,f])

= [g] + merge([e,a,b,o], [f,b,c,o], [e,f])

= [g,e] + merge([a,b,o], [f,b,c,o], [f])

= [g,e,a] + merge([b,o], [f,b,c,o], [f])

= [g,e,a,f] + merge([b,o], [b,c,o])

= [g,e,a,f,b] + merge([o], [c,o])

= [g,e,a,f,b,c] + merge([o], [o])

= [g,e,a,f,b,c,o]

自己實現了乙個mro演算法

from exceptions import exception

def c3_lineration(kls):

if len(kls.__bases__) == 1:

return [kls, kls.__base__]

else:

l = [c3_lineration(base) for base in kls.__bases__]

return [kls] + merge(l)

def merge(args):

if args:

for mro_list in args:

for class_type in mro_list:

for comp_list in args:

if class_type in comp_list[1:]:

break

else:

next_merge_list =

for arg in args:

if class_type in arg:

arg.remove(class_type)

if arg:

else:

return [class_type] + merge(next_merge_list)

else:

raise exception

else:

return

class a(object):pass

class b(object):pass

class c(object):pass

class e(a,b):pass

class f(b,c):pass

class g(e,f):pass

print c3_lineration(g)

Python的多重繼承問題 MRO和C3演算法

有乙個sina的blog介紹的很好 python 多重繼承mro mro即method resolution order,主要用於在多繼承時判斷調的屬性的路徑 來自於哪個類 之前檢視了很多資料,說mro是基於深度優先搜尋演算法的。但不完全正確在python2.3之前是基於此演算法,但從python2...

python 多重繼承

python和c 一樣,支援多繼承。概念雖然容易,但是困難的工作是如果子類呼叫乙個自身沒有定義的屬性,它是按照何種順序去到父類尋找呢,尤其是眾多父類中有多個都包含該同名屬性。對經典類和新式類來說,屬性的查詢順序是不同的。現在我們分別看一下經典類和新式類兩種不同的表現 經典類 usr bin pyth...

Python多重繼承

class printa namea printa def set value self,a self.a a def set namea self,namea printa.namea namea def info self print printa s,s printa.namea,self.a...