Python高级编程:类和实例属性的查找顺序—mro查找
一、?mro查找定義
如果多個類繼承父類,然后又被多個類繼承這種復雜的問題,可以使用mro方法
class D:pass class C(D):pass class B(D):pass class A(B,C):passprint(A.__mro__) 輸出結果: (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)二、?mro查找應用
自從Python2.3后使用C3 MRO算法,關于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:對應圖2菱形繼承有問題。加入現在有一個方法get_value, C、D中存在get_value, A、B不存在get_value, 那么當A調用get_value時,調用的就是D中的get_value方法。C中永遠起不到重載D中方法的作用。因此DFS對菱形繼承有問題,在python2之后改為了廣度優先算法。
BFS:圖2的菱形繼承問題解決了,但是圖1的繼承又出現了問題。?以圖1來說明,如果C和D中有一個同名的方法get_value, B和A中沒有get_value方法,那么A調用get_value時,就會調用C中的方法,而實際上B和D應該看成一個整體,在B中不存在就應該去父類中搜索。因此在Python2.3后,提出了C3 MRO算法,解決了上面的兩個問題。
那么如何查看C3 MRO算法的搜索順序呢, 調用__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 #結果:(<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 #結果:(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)Python2.3到Python2.7:經典類、新式類和平發展
因為之前的BFS存在較大的問題,所以從Python2.3開始新式類的MRO取而代之的是C3算法,我們可以知道C3算法肯定解決了單調性問題,和只能繼承無法重寫的問題。C3算法具體實現稍后講解。
MRO的C3算法順序如下圖:看起簡直是DFS和BFS的合體有木有。但是僅僅是看起來像而已
三、?C3算法原理
Python3到至今:新式類一統江湖
Python3開始就只存在新式類了,采用的MRO也依舊是C3算法。
我們要解決兩個問題:單調性問題和不能重寫的問題。
很容易發現要解決單調性,只要保證從根(A)到葉(object),從左到右的訪問順序即可。
那么對于只能繼承,不能重寫的問題呢?先分析這個問題的本質原因,主要是因為先訪問了子類的父類導致的。那么怎么解決只能先訪問子類再訪問父類的問題呢?如果熟悉圖論的人應該能馬上想到拓撲排序,這里引用一下百科的的定義:
對一個有向無環圖(Directed Acyclic Graph簡稱DAG)G進行拓撲排序,是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u和v,若邊(u,v)∈E(G),則u在線性序列中出現在v之前。通常,這樣的線性序列稱為滿足拓撲次序(Topological Order)的序列,簡稱拓撲序列。簡單的說,由某個集合上的一個偏序得到該集合上的一個全序,這個操作稱之為拓撲排序。
因為拓撲排序肯定是根到葉(也不能說是葉了,因為已經不是樹了),所以只要滿足從左到右,得到的拓撲排序就是結果,關于拓撲排序算法,大學的數據結構有教,這里不做講解,不懂的可以自行谷歌或者翻一下書,建議了解完算法再往下看。
那么模擬一下例子的拓撲排序:首先找入度為0的點,只有一個A,把A拿出來,把A相關的邊剪掉,再找下一個入度為0的點,有兩個點(B,C),取最左原則,拿B,這是排序是AB,然后剪B相關的邊,這時候入度為0的點有E和C,取最左。這時候排序為ABE,接著剪E相關的邊,這時只有一個點入度為0,那就是C,取C,順序為ABEC。剪C的邊得到兩個入度為0的點(DF),取最左D,順序為ABECD,然后剪D相關的邊,那么下一個入度為0的就是F,然后是object。那么最后的排序就為ABECDFobject。
參考文章:
MRO算法
4-6 類和實例屬性的查找順序----mro查找
總結
以上是生活随笔為你收集整理的Python高级编程:类和实例属性的查找顺序—mro查找的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python中包(package)的调用
- 下一篇: Python报错:UnicodeDeco