11.1 方法解析順序
方法解析順序 (Method Resolution Order, MRO) 決定了 Python 在類層次結構中搜索方法和屬性的順序。這在使用多重 繼承時尤其重要,因為類可能從多個父類繼承屬性和方法。
簡單來說,有一個固定的順序(或更確切地說,是算法), 根據這個順序 Python 瀏覽類的繼承樹。這個算法 保證了方法搜索的正確順序,可以描述為:
C3線性化算法
C3線性化算法通過組合以下方式來確定MRO:
- 類本身。
- 按照它們被列舉的順序的父類清單。
- 以相同順序的父類的MRO。
C3線性化算法規則
-
保持方法的局部順序: 如果類
A
在類B
之前列出,那麼類A
的所有方法都應該在 類B
的方法之前考慮。 -
保持父類的順序: 如果類
A
是類B
的父類,那麼類A
的所有方法都應該 在類B
的方法之前考慮。 -
考慮繼承順序: 如果類
C
是 兩個或多個類的父類,那麼類C
方法的順序應該在所有這些類的MRO中保持。
算法步驟:
步驟 1. 從類本身開始:
總是從調用方法的類本身開始。
步驟 2. 按照列舉順序添加基類:
在當前類之後,按照繼承時指定的順序檢查其基類。
步驟 3. 瀏覽父類:
那裡查找字段和方法。
步驟 4. 合併父類的MRO:
如果同一個基類通過多個路徑繼承,它 只被檢查一次並且按正確的順序(其餘時間都將被忽略)。
對於已經了解“算法和數據結構”主題的人來說,這 是深度優先搜索,而不是廣度優先搜索。
11.2 檢查MRO
在 Python 中,可以使用屬性 __mro__
或函數
mro()
檢查類的字段和方法的搜索順序。
範例:
class A:
def method(self):
print("A")
class B(A):
def method(self):
print("B")
class C(A):
def method(self):
print("C")
class D(B, C):
def method(self):
print("D")
# 檢查 MRO
print(D.__mro__)
輸出將是:
(<class '__main__.D'>,
<class '__main__.B'>,
<class '__main__.C'>,
<class '__main__.A'>,
<class 'object'>)
這顯示了 Python 將如何搜索方法和屬性的順序:
D
: Python 首先檢查類D
中的方法。-
B
: 然後 Python 檢查類B
中的方法(第一個 父類)。 -
C
: 如果在類B
中找不到方法,Python 檢查 類C
中的方法(第二個父類)。 -
A
: 如果在類B
和C
中找不到方法,Python 檢查類A
中的方法。 -
object
: 最後,Python 檢查 基礎類object
中的方法。
11.3 使用 super()
和 MRO
函數 super()
遵循 MRO 來正確順序呼叫
父類的方法。考慮以下 super()
的使用範例:
class A:
def method(self):
print("A")
super().method()
class B(A):
def method(self):
print("B")
super().method()
class C(A):
def method(self):
print("C")
super().method()
class D(B, C):
def method(self):
print("D")
super().method()
d = D()
d.method()
輸出將如下:
D
B
C
A
搜索順序 (MRO)
1. 調用類 D
的 method
方法:
- Python 首先檢查類
D
並在那裡找到方法。 - 方法
D.method()
執行並打印"D"
。 -
然後調用
super().method()
,它遵循 MRO 來調用 下一個方法。
2. 調用類 B
的 method
方法:
- 根據 MRO,
D
之後的類是B
。 - 方法
B.method()
執行並打印"B"
。 -
然後調用
super().method()
,它遵循 MRO 來調用 下一個方法。
3. 調用類 C
的 method
方法:
- MRO 中
B
之後的類是C
。 - 方法
C.method()
執行並打印"C"
。 -
然後調用
super().method()
,它遵循 MRO 來調用 下一個方法。
4. 調用類 A
的 method
方法:
- MRO 中
C
之後的類是A
。 - 方法
A.method()
執行並打印"A"
。 -
然後調用
super().method()
,但因為A
沒有其他 父類方法method
(除了object
),所以調用結束。
GO TO FULL VERSION