在Python中,當定義一個類別時,可以指定它的父類別。一個子類別繼承了其所有父類別的屬性和方法,並且可以添加自己特有的屬性和方法。
然而,如果一個類別有多個直接父類,那麼這些父類別之間可能會存在重名的屬性和方法。為了正確地呼叫這些屬性和方法,Python使用了一種稱為「方法解析順序」(Method Resolution Order,MRO)的演算法來決定屬性和方法的查找順序。
在Python 2.x中,MRO採用深度優先搜尋演算法(DFS)實作。這種演算法存在一些問題,導致在某些情況下無法正確解析方法呼叫順序。例如:
class A: def foo(self): print("A.foo") class B(A): pass class C(A): def foo(self): print("C.foo") class D(B, C): pass d = D() d.foo() # 输出"A.foo",而不是"C.foo"
在上述程式碼中,類別D繼承了類別B和類別C,並且類別C重寫了類別A的foo()方法。因此,在呼叫物件d的foo()方法時,理論上應該先呼叫類別C中的foo()方法。然而,由於Python 2.x中採用的是DFS演算法,它會先遍歷類別B,然後再遍歷類別C,最後才會遍歷類別A。因此,最終呼叫的是類別A中的foo()方法,而不是類別C中的foo()方法。
為了解決這個問題,Python 2.3引入了C3演算法,它使用拓樸排序演算法來計算MRO列表,從而保證呼叫方法時的正確性。 C3演算法的基本原理如下:
新式類別(即明確繼承object或隱式繼承object的類別)的MRO清單按照廣度優先搜尋(BFS)演算法進行計算。
對於每個類,其MRO清單應滿足以下三個條件:
子類的MRO清單要排在父類別的MRO列表前面。
如果兩個父類別都在一個子類別的MRO清單中出現,則它們在該清單中的相對順序要與它們在該子類別的直接父類別中出現的相對順序相同。
一個類別不能在其MRO清單中出現兩次以上。
這種演算法能夠正確處理上述範例程式碼中的情況,從而保證呼叫方法時的正確性。
在Python 3中,可以透過__mro__
屬性來查看類別的MRO清單。例如:
class A: def foo(self): print("A.foo") class B(A): pass class C(A): def foo(self): print("C.foo") class D(B, C): pass print(D.__mro__)
輸出結果為:
(025dcfa56ce70cf61f231bd7d6b09a90, d3d10dde313d07caf2874a0faa31cc27, 8a1d825241d138e74588411ff30b3bba, d65e71c32c2035ca4f3e3c46100a7a5f, 0b6b3070adce8118f880cf43f8bc8037)
其中,9feb4194ec50eecacec2aeb187aaba71
表示類別D本身,d3d10dde313d07caf2874a0faa31cc27
和264899d62e4ca0da0ab3f6eed2baa002
分別表示類別D的父類別B和C,d65e71c32c2035ca4f3e3c46100a7a5f
表示類別B和C的共同父類別A,0b6b3070adce8118f880cf43f8bc8037
表示所有新式類的基底類。這個列表的順序就是Python運行時查找屬性和方法的順序。
以上是python子類別在多繼承中怎麼使用MRO的詳細內容。更多資訊請關注PHP中文網其他相關文章!