當子類繼承父類的一些方法并且子類已經(jīng)覆蓋此方法時,我們?nèi)绾握{(diào)用父類中的函數(shù)潜沦?這里提供兩種調(diào)用方式:
- 通過在子類中實例化父類的方式調(diào)用父類函數(shù)
class Base:
def __init__(self):
print("Base.__init__")
class A(Base):
Base.__init__(self)
print("A.__init__")
這種方法比較奔放萄涯,對于大多數(shù)還是正常的,但是對于多重繼承的時候會重復調(diào)用父類唆鸡。解決辦法就是使用第二種方法進行調(diào)用涝影。
- 通過supper調(diào)用父類函數(shù)
class Base:
def __init__(self):
print("Base.__init__")
class A(Base):
def __init__(self):
Base.__init__(self)
print("A.__init__")
class B(Base):
def __init__(self):
Base.__init__(self)
print("B.__init__")
class C(A, B):
def __init__(self):
A.__init__(self)
B.__init__(self)
print("C.__init__")
運行一下代碼:
>>>c = C()
Base.__init__
A.__init__
Base.__init__
B.__init__
C.__init__
這里可以清晰的看到當我們進行多重繼承的時候父類被多次調(diào)用,看似沒有任何問題喇闸,當時當代碼復雜到一定程度時會摸不著頭腦袄琳,產(chǎn)生的錯誤莫名其妙。我們再使用supper進行相同的操作:
class Base:
def __init__(self):
print("Base.__init__")
class A(Base):
def __init__(self):
supper().__init__()
print("A.__init__")
class B(Base):
def __init__(self):
supper().__init__()
print("B.__init__")
class C(A, B):
def __init__(self):
supper().__init__()
print("C.__init__")
運行代碼:
>>> c = C()
Base.__init__
A.__init__
B.__init__
C.__init__
從得到的結果跟上面的代碼運行結果進行對比可以得出以下結果:
當我們使用supper進行父類方法調(diào)用時燃乍,只會調(diào)用一次父類的方法
我們再來看看這個調(diào)用是怎樣實現(xiàn)的:
python進行繼承時唆樊,針對每個定義的類,python都會計算出一個方法解析順序列表(MRO)MRO只是簡單地針對所有的基類進行現(xiàn)行排列刻蟹。實現(xiàn)繼承時逗旁,python會從MRO列表中最左邊的類開始,從左到右進行查找舆瘪,直到找到待查的屬性時為止片效。這是python繼承的機制,那么MRO又是怎樣實現(xiàn)的英古?
簡單來說這是針對父類的一種歸并排序淀衣,需要滿足3個約束:
- 先檢查子類再檢查父類
- 有多個父類時,按照MRO列表的順序依次檢查
- 如果下一個帶選的類中出現(xiàn)兩個或多個合法的選擇召调,那么就從第一個父類中選擇膨桥。
再來回顧剛才的例子:
MRO會控制最終遍歷整個MRO列表,并且每個方法只會被調(diào)用一次唠叛。這里就是剛才我們使用supper時為何只調(diào)用一次父類方法的原因只嚣。