python順序 Python的方法解析順序

2021-10-18 16:04:13 字數 3309 閱讀 1157

基本的定義

讓我們從一些基本的定義開始。

給定乙個名為c的類,在複雜的多繼承場景下為它確定過載方法的順序,即指定c的祖先的順序,是非常重要的。

c祖先(包括c自己)的列表由近到遠進行排序,被稱為類優先順序列表,或者c的線性化。

方法解析順序(mro)是構成這種線性化的一組規則。在python中,c的mro和c的線性化是同乙個意思。

例如,在單繼承的情況下,如果c是c1的子類,並且c1是c2的子類,則c的線性化僅僅是列表[c, c1, c2]。然而在多繼承的情況下,線性化的構造更加麻煩,因為構建乙個同時滿足尊重區域性優先順序順序和單調性的線性化是很困難的。

當滿足以下條件時,mro是單調的:如果在c的mro中c1排在c2之前,那麼任何c的子類的mro中c1都應該在c2中。如果違反了這樣規則,可能就會引入一些不容易察覺的bug。

不是所有的類都允許線性化。在一些複雜的多繼承場景下,既想符合所有期望的屬性又想生成派生類是不可能的。

考慮下面的情況。

o = object

class x(o): pass

class y(o): pass

class a(x, y): pass

class b(y, x): pass

class c(a, b): pass

不可能從a和b中派生出c,因為在a的mro中x排在y前面,而在b的mro中y排在x前面。因此c的mro會是有歧義的。

在python2.3或以上版本中,上面的情況會丟擲乙個異常。

typeerror: error when calling the metaclass bases

cannot create a consistent method resolution

order (mro) for bases y, x

c3 mro

python2.3使用了c3方法。

下面的示例中,均用c1c2...cn來表示列表[c1, c2, ..., cn]。

第乙個元素是列表的頭:

head = c1

其它列表中的元素是尾

tail = c2...cn

下面用c + (c1c2...cn) = cc1c2...cn

來表示列表的相加

[c] + [c1,c2,...,cn]

下面來說明python2.3中mro的具體演算法。

假設類c處於多繼承的場景下,c繼承於基類b1,b2,...bn。現在來計算c的mro。

規則如下:

類c的線性化是c加上父類的線性化和父類列表的合併。

表示式如下:

l[c(b1...bn)] = c + merge(l(b1)...l[bn], b1...bn)

特別的,如果c是object,那麼c的mro為

l[object] = object

這裡的關鍵在於merge。其輸入是一組列表,按照如下方式輸出乙個列表:

檢查第乙個列表的head,比如l[b1][0]

如果這個列表的head不在其它列表的tail中,則將其加到c的線性化中,並從merge的所有列表中刪除這個元素,然後回到步驟1;否則,取出下乙個列表的head,繼續該步驟

重複上述步驟,知道列表為空或者不能再找出可以輸出的元素。如果是前一種情況,演算法結束;如果是後一種情況,說明無法構建繼承關係,python會丟擲異常。

如果是在單繼承的場景下,計算是很簡單的。

l[c(b)] = c + merge(l[b], b) = c + l(b)

但是在多繼承的情況下,會稍微麻煩一點。

例子比如下面的**

o = object

class f(o): pass

class e(o): pass

class d(o): pass

class c(d, f): pass

class b(d, e): pass

class a(b, c): pass

繼承樹類o,d,e的mro是很顯然的

l[o] = o

l[d] = d o

l[e] = e o

l[f] = f o

類b的mro公式如下

l[b] = b + merge(do, eo, de)

// d 沒有在其它的列表的尾**現,因此將其取出

l[b] = b d + merge(o, eo, e)

// o 在其它列表的尾**現了。進入下乙個列表

// e 沒有在其它列表的尾**現,因此將其取出

l[b] = b d e + merge(o, o)

// o 沒有在其它列表的尾**現,因此將其取出

l[b] = b d e o

通過同樣的流程可以算出c的mro

l[c] = c + merge(do, fo, df)

= c + d + merge(o, fo, f)

= c + d + f + merge(o, o)

= c d f o

現在再來計算a的mro

l[a] = a + merge(bdeo, cdfo, bc)

= a + b + merge(deo, cdfo, c)

= a + b + c + merge(deo, dfo)

= a + b + c + d + merge(eo, fo)

= a + b + c + d + e + merge(o, fo)

= a + b + c + d + e + f + merge(o, o)

= a + b + c + d + e + f + o

上面的例子中,根據繼承的級別線性化得到了正確的結果。但是並不是所有的情況都能算出結果。

比如下面的例子。

o = object

class f(o): pass

class e(o): pass

class d(o): pass

class c(d, f): pass

class b(e, d): pass

class a(b, c): pass

和上面的例子一樣,可以很快算出o,x,y,a,b的mro。

l[o] = o

l[x] = x o

l[y] = y o

l[a] = a x y o

l[b] = b y x o

但是算到c的時候會有一點問題

l[c] = c + merge(axyo, byxo, ab)

= c + a + merge(xyo, byxo, b)

= c + a + b + merge(xyo, yxo)

// x在yxo的尾部,y在xyo的尾部,計算無法繼續進行

這個時候python2.3會丟擲異常,阻止建立c。

python的執行順序 python之執行順序隨記

python的執行順序一直都是很令人頭疼,簡單隨記了一些 1 正常順序執行。print 1 a 2l 3 這個就不附結果了,都能猜得到,這種按順序執行。2 函式的執行過程 coding utf 8 defa print is a defb a print b use a defc b print c...

python繼承順序

python和c 一樣,支援多繼承。概念雖然容易,但是困難的工作是如果子類呼叫乙個自身沒有定義的屬性,它是按照何種順序去到父類尋找呢,尤其是眾多父類中有多個都包含該同名屬性。class p1 object def foo self print p1 foo class p2 object def f...

順序查詢(python)

根據python中列表查詢某乙個數 alist 1,2,3,4,5,6,3,8,9 sign false 初始值為沒找到 x int input 請輸入要查詢的整數 for i in range len alist if alist i x print 整數 d在列表中,在第 d個數 x,i 1 s...