Python高级编程:类和实例属性的查找顺序—mro查找
一、?mro查找定義
如果多個類繼承父類,然后又被多個類繼承這種復(fù)雜的問題,可以使用mro方法
class D:pass class C(D):pass class B(D):pass class A(B,C):passprint(A.__mro__) 輸出結(jié)果: (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)二、?mro查找應(yīng)用
自從Python2.3后使用C3 MRO算法,關(guān)于C3 MRO算法的詳情,參考The Python 2.3 Method Resolution Order?
| 圖一 | A->B->D->C->E? | A->B->C->D->E? |
| 圖二 | A->B->D->C? | A->B->C->D? |
?
DFS:對應(yīng)圖2菱形繼承有問題。加入現(xiàn)在有一個方法get_value, C、D中存在get_value, A、B不存在get_value, 那么當(dāng)A調(diào)用get_value時,調(diào)用的就是D中的get_value方法。C中永遠(yuǎn)起不到重載D中方法的作用。因此DFS對菱形繼承有問題,在python2之后改為了廣度優(yōu)先算法。
BFS:圖2的菱形繼承問題解決了,但是圖1的繼承又出現(xiàn)了問題。?以圖1來說明,如果C和D中有一個同名的方法get_value, B和A中沒有g(shù)et_value方法,那么A調(diào)用get_value時,就會調(diào)用C中的方法,而實(shí)際上B和D應(yīng)該看成一個整體,在B中不存在就應(yīng)該去父類中搜索。因此在Python2.3后,提出了C3 MRO算法,解決了上面的兩個問題。
那么如何查看C3 MRO算法的搜索順序呢, 調(diào)用__mro__屬性
圖1: class D(object):passclass E(object):passclass B(D):passclass C(E):pass class A(B, C):passprint(A.__mro__) #MRO順序:A-->B-->D-->C-->E #結(jié)果:(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>) 圖2class D(object):passclass B(D):passclass C(D):pass class A(B, C):passprint(A.__mro__) # MRO順序:A-->B-->C-->D #結(jié)果:(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)Python2.3到Python2.7:經(jīng)典類、新式類和平發(fā)展
因?yàn)橹暗腂FS存在較大的問題,所以從Python2.3開始新式類的MRO取而代之的是C3算法,我們可以知道C3算法肯定解決了單調(diào)性問題,和只能繼承無法重寫的問題。C3算法具體實(shí)現(xiàn)稍后講解。
MRO的C3算法順序如下圖:看起簡直是DFS和BFS的合體有木有。但是僅僅是看起來像而已
三、?C3算法原理
Python3到至今:新式類一統(tǒng)江湖
Python3開始就只存在新式類了,采用的MRO也依舊是C3算法。
我們要解決兩個問題:單調(diào)性問題和不能重寫的問題。
很容易發(fā)現(xiàn)要解決單調(diào)性,只要保證從根(A)到葉(object),從左到右的訪問順序即可。
那么對于只能繼承,不能重寫的問題呢?先分析這個問題的本質(zhì)原因,主要是因?yàn)橄仍L問了子類的父類導(dǎo)致的。那么怎么解決只能先訪問子類再訪問父類的問題呢?如果熟悉圖論的人應(yīng)該能馬上想到拓?fù)渑判?#xff0c;這里引用一下百科的的定義:
對一個有向無環(huán)圖(Directed Acyclic Graph簡稱DAG)G進(jìn)行拓?fù)渑判?#xff0c;是將G中所有頂點(diǎn)排成一個線性序列,使得圖中任意一對頂點(diǎn)u和v,若邊(u,v)∈E(G),則u在線性序列中出現(xiàn)在v之前。通常,這樣的線性序列稱為滿足拓?fù)浯涡?Topological Order)的序列,簡稱拓?fù)湫蛄小:唵蔚恼f,由某個集合上的一個偏序得到該集合上的一個全序,這個操作稱之為拓?fù)渑判颉?br /> 因?yàn)橥負(fù)渑判蚩隙ㄊ歉饺~(也不能說是葉了,因?yàn)橐呀?jīng)不是樹了),所以只要滿足從左到右,得到的拓?fù)渑判蚓褪墙Y(jié)果,關(guān)于拓?fù)渑判蛩惴?#xff0c;大學(xué)的數(shù)據(jù)結(jié)構(gòu)有教,這里不做講解,不懂的可以自行谷歌或者翻一下書,建議了解完算法再往下看。
那么模擬一下例子的拓?fù)渑判?#xff1a;首先找入度為0的點(diǎn),只有一個A,把A拿出來,把A相關(guān)的邊剪掉,再找下一個入度為0的點(diǎn),有兩個點(diǎn)(B,C),取最左原則,拿B,這是排序是AB,然后剪B相關(guān)的邊,這時候入度為0的點(diǎn)有E和C,取最左。這時候排序?yàn)锳BE,接著剪E相關(guān)的邊,這時只有一個點(diǎn)入度為0,那就是C,取C,順序?yàn)锳BEC。剪C的邊得到兩個入度為0的點(diǎn)(DF),取最左D,順序?yàn)锳BECD,然后剪D相關(guān)的邊,那么下一個入度為0的就是F,然后是object。那么最后的排序就為ABECDFobject。
參考文章:
MRO算法
4-6 類和實(shí)例屬性的查找順序----mro查找
總結(jié)
以上是生活随笔為你收集整理的Python高级编程:类和实例属性的查找顺序—mro查找的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python中包(package)的调用
- 下一篇: Python报错:UnicodeDeco