摘要:經常有朋友問,學 Python 面向物件時,翻閱別人代碼,會發現一個 super() 函式,那這個函式的作用到底是什么?
本文分享自華為云社區《Python中的super函式怎么學,怎么解?》,作者: 夢想橡皮擦,
實戰場景
經常有朋友問,學 Python 面向物件時,翻閱別人代碼,會發現一個 super() 函式,那這個函式的作用到底是什么?
super() 函式的用途如下,在子類中呼叫父類的方法,多用于類的繼承關系,
其語法格式如下所示:
super(type[, object-or-type])
引數說明如下:
- type:類,可選引數
- object-or-type:物件或類,一般為 self,也是可選引數,
回傳值是代理物件,
可以直接查詢官方幫助手冊:
help(super)
輸出資訊如下所示:
Help on class super in module builtins: class super(object) | super() -> same as super(__class__, <first argument>) | super(type) -> unbound super object | super(type, obj) -> bound super object; requires isinstance(obj, type) | super(type, type2) -> bound super object; requires issubclass(type2, type) | Typical use to call a cooperative superclass method: | class C(B): | def meth(self, arg): | super().meth(arg) | This works for class methods too: | class C(B): | @classmethod | def cmeth(cls, arg): | super().cmeth(arg)
對輸出結果進行分析之后,可以得到如下結論:
- super 類是一個繼承自 object 的類,super() 函式就是對該類的實體化;
- 呼叫 super() 實體化之后,回傳一個 super 物件;
- super() 引數有四種搭配,具體看上述輸出;
實戰編碼
單繼承使用
直接看一下單繼承相關代碼,其中使用類名去呼叫父類方法,
class A: def funA(self): print("執行 A ,輸出橡皮擦") class B(A): def funB(self): # self 表示 B 類的實體 A.funA(self) print("執行 B ,輸出鉛筆") b = B() b.funB()
上述代碼在 B 類中增加了 funB 函式,并且去呼叫 A 類中的 funA 函式,此時輸出的內容如下所示:
執行 A ,輸出橡皮擦
執行 B ,輸出鉛筆
如果將上述代碼修改為 super() 函式呼叫父類方法,可以使用下述代碼:
class A: def funA(self): print("執行 A ,輸出橡皮擦") class B(A): def funB(self): # 注意 super() 函式的用法 super().funA() print("執行 B ,輸出鉛筆") b = B() b.funB()
上述代碼與之前的運行結果一致,在單繼承的層級結構中,super 可以直接參考父類,即在子類中不需要使用父類名呼叫父類方法,而使用 代理物件(super 物件) 去呼叫,這樣的好處就是當父類名改變或繼承關系發生改變時,我們不需要對呼叫進行反復修改,
接下來看一下多繼承情況下,super() 函式的實戰場景,
class A: def funA(self): print("執行 A ,輸出橡皮擦") class B(A): def funB(self): # 注意 super() 函式的用法 super().funA() print("執行 B ,輸出鉛筆") b = B() b.funB()
此時輸出的結果是 AAA,可以看到 super 匹配到的資料是 A 類中的 run 函式,也就是最左側類中的方法,下面修改一下各類中 run 函式的名稱,使其存在差異,
class A: def run1(self): print('AAA') class B: def run2(self): print('BBB') class C: def run3(self): print('CCC') class D(A, B, C): def run(self): # 呼叫 B 中 run2 super().run2() d = D() d.run()
當一個類繼承多個類時,如果第一個父類中沒有提供該方法,當前類實體就會通過 __mro__ 屬性進行向上搜索,如果到 object 類都沒有檢索到該方法,就會引發 AttributeError 例外,
基于上述邏輯,我們可以擴展一下,使用 super() 函式中的引數,
class A: def run(self): print('AAA') class B: def run(self): print('BBB') class C: def run(self): print('CCC') class D(A, B, C): def run(self): # 呼叫 C 中 run super(B, self).run() d = D() d.run()
此時輸出的結果是 CCC,該結果輸出表示了使用 super 函式之后,可以使用 super(類,self) 指定以哪個類為起點檢索父類中的方法,上述代碼設定的 B,就表示從 B 開始檢索,后續找到了 C 類,其中包含 run() 方法,所以輸出 CCC,
__mro__ 屬性的說明,
MRO 是 method resolution order,即方法決議順序,其本質是繼承父類方法時的順序表,
在 Python 中可以使用內置屬性 __mro__ 查看方法的搜索順序,例如下述代碼,重點查看輸出部分內容,
class A: def run(self): print('AAA') class B: def run(self): print('BBB') class C: def run(self): print('CCC') class D(A, B, C): def run(self): # 呼叫 C 中 run super(B, self).run() print(D.__mro__)
輸出的結果如下所示:
(<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
你可以修改一下繼承順序,然后得到不同的輸出結果,
(<class '__main__.D'>, <class '__main__.A'>, <class '__main__.C'>, <class '__main__.B'>, <class 'object'>)
在搜索方法的時候,是按照 __mro__ 的輸出結果從左到右進行順序查找的,邏輯如下:
A. 找到方法,停止檢索;
B. 沒有找到,繼續檢索下一類;
C. 如果到最后都沒有找到,程式報錯,
點擊關注,第一時間了解華為云新鮮技術~
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/508772.html
標籤:其他
