有乙個sina的blog介紹的很好:python 多重繼承mro
mro即method resolution order,主要用於在多繼承時判斷調的屬性的路徑(來自於哪個類)。之前檢視了很多資料,說mro是基於深度優先搜尋演算法的。但不完全正確在python2.3之前是基於此演算法,但從python2.3起應用了新演算法: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演算法中就是非法的。
判斷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
defc3_lineration
(kls):if
len(kls.__bases__)==1
:return
[kls, kls.__base__]
else
: l =
[c3_lineration(base)
for base in kls.__bases__]
[base for base in kls.__bases__]
)return
[kls]
+ merge(l)
defmerge
(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
classa(
object):
pass
classb(
object):
pass
classc(
object):
pass
class
e(a,b)
:pass
class
f(b,c)
:pass
class
g(e,f)
:pass
print c3_lineration(g)
python的多重繼承
在設計類的繼承關係時,通常,主線都是單一繼承下來的,如果需要 混入 額外的功能,通過多重繼承就可以實現,這種設計通常稱之為mixin。class animal object pass class mammal animal pass class runnable object def run sel...
python的多重繼承
python和c 一樣,支援多繼承。概念雖然容易,但是困難的工作是如果子類呼叫乙個自身沒有定義的屬性,它是按照何種順序去到父類尋找呢,尤其是眾多父類中有多個都包含該同名屬性。對經典類和新式類來說,屬性的查詢順序是不同的。現在我們分別看一下經典類和新式類兩種不同的表現 經典類 usr bin pyth...
python 多重繼承
python和c 一樣,支援多繼承。概念雖然容易,但是困難的工作是如果子類呼叫乙個自身沒有定義的屬性,它是按照何種順序去到父類尋找呢,尤其是眾多父類中有多個都包含該同名屬性。對經典類和新式類來說,屬性的查詢順序是不同的。現在我們分別看一下經典類和新式類兩種不同的表現 經典類 usr bin pyth...