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...