Python super( )函數(shù)用法總結(jié)
一、super( ) 的用途
了解 super() 函數(shù)之前,我們首先要知道 super() 的用途是啥?
- 主要用來在子類中調(diào)用父類的方法。
- 多用于多繼承問題中,解決查找順序(MRO)、重復(fù)調(diào)用(鉆石繼承)等種種問題。
二、了解 super 的基礎(chǔ)信息
語法格式:
super([type[, object-or-type]])
函數(shù)描述:
返回一個代理對象,它會將方法調(diào)用委托給 type 的父類或兄弟類。
參數(shù)說明:
type —— 類,可選參數(shù)。object-or-type —— 對象或類,一般是 self,可選參數(shù)。
返回值:
super object —— 代理對象。
help 幫助信息:
>>> 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 的類,調(diào)用 super() 函數(shù)其實就是 super 類的實例化。
- 根據(jù)官方文檔的解釋 super() 函數(shù)返回的對象 —— super object,就是一個代理對象。
- super() 有四種參數(shù)的組合形式。
- super()適用于類的靜態(tài)方法。
三、典型用法
3.1 單繼承問題
首先我們看一個最基本的子類調(diào)用父類方法的示例:
>>> class A: def funxx(self): print("執(zhí)行 A 中的 funxx 方法 ... ...") >>> class B(A): def funxx(self): A.funxx(self) # 通過類名調(diào)用父類中的同名方法,self 參數(shù)代表 B 類的實例對象 b print("執(zhí)行 B 中的 funxx 方法 ... ...") >>> b = B() >>> b.funxx() 執(zhí)行 A 中的 funxx 方法 ... ... 執(zhí)行 B 中的 funxx 方法 ... ...
- 定義一個繼承自 A 類的子類 B,并在 B 類中重寫 funxx() 方法,B 中的 funxx() 是對 A 中的 funxx() 功能的拓展。
- 因為是拓展了 A 類的 funxx() 方法的功能,所以其任然保留了原功能,即要在子類 B 中調(diào)用父類的同名方法來實現(xiàn)原有功能。
- 上面的示例中是通過 A 類類名調(diào)用 A 類中的同名方法來實現(xiàn)的,而第一個參數(shù) self 實際傳遞的是 B 類的實例 b。
使用 super() 函數(shù)來實現(xiàn)父類方法的調(diào)用:
>>> class A: def funxx(self): print("執(zhí)行 A 中的 funxx 方法 ... ...") >>> class B(A): def funxx(self): super().funxx() print("執(zhí)行 B 中的 funxx 方法 ... ...") >>> b = B() >>> b.funxx() 執(zhí)行 A 中的 funxx 方法 ... ... 執(zhí)行 B 中的 funxx 方法 ... ...
- 通過執(zhí)行的結(jié)果可以看出實現(xiàn)了和普通類名調(diào)用的結(jié)果是一樣的。
- 在具有單繼承的類層級結(jié)構(gòu)中,super 引用父類而不必顯式地指定它們的名稱,從而令代碼更易維護(hù)。(官方文檔描述)
- 也就是說,在子類中不再用父類名調(diào)用父類方法,而是用一個代理對象調(diào)用父類方法,這樣當(dāng)父類名改變或者繼承關(guān)系發(fā)生變化時,不用對每個調(diào)用處都進(jìn)行修改。
3.2 單繼承問題拓展
在 help()
的幫助信息中,也說明了類中使用 super()
不帶參數(shù)的形式等同于 super(__class__, <first argument>)
這種形式。這也是 Python 2.x 和 Python 3.x 關(guān)于 super()
的區(qū)別。
改寫之前的單繼承問題的代碼:
>>> class A: def funxx(self): print("執(zhí)行 A 中的 funxx 方法 ... ...") >>> class B(A): def funxx(self): super(B, self).funxx() print("執(zhí)行 B 中的 funxx 方法 ... ...") >>> b = B() >>> b.funxx() 執(zhí)行 A 中的 funxx 方法 ... ... 執(zhí)行 B 中的 funxx 方法 ... ...
- 基本的調(diào)用方法
A.funxx(self)
,其中 self 指代實例對象 b。用語言描述為:實例對象 b 通過 A 類名調(diào)用方法funxx()
。 - 官方描述:返回一個代理對象,它會將方法調(diào)用委托給 type 的父類或兄弟類。用語言描述為:代理對象 super 通過 type 的父類或兄弟類調(diào)用其中的方法。
- 我們發(fā)現(xiàn) super 是通過參數(shù)設(shè)置來選擇調(diào)用哪個父類的方法。其中第二個參數(shù)給出 MRO(方法解析順序),也就是搜索目標(biāo)方法的順序,第一個參數(shù)則給出搜索目標(biāo)方法的范圍。
- 例如
super(B, self)
,第一個參數(shù)為 B,第二個參數(shù) self 為實例 b,其所在類的繼承順序(MRO)為:B→A→object。所以調(diào)用時是在 B 的父類 A 中尋找,如找不到目標(biāo)方法則會在更上一層的 object 中尋找。
示例:
class A: pass class B(A): pass class C(A): def funxx(self): print("找到 funxx() 位于 C 中...") class D(A): pass class E(B, C): pass class F(E, D): def funff(self): print("執(zhí)行 F 中的 funff()...") super(E, self).funxx() print(f"F 類的 MRO : {F.__mro__}") f = F() f.funff()
運行結(jié)果:
F 類的 MRO : (<class '__main__.F'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>) 執(zhí)行 F 中的 funff()... 找到 funxx() 位于 C 中...
- 我們可以看出 F 類的 MRO:F→E→B→C→D→A→object。
super()
函數(shù)的第一個參數(shù)為:E,目標(biāo)是調(diào)用 E 類的父類 B 中的funxx()
方法,可惜 B 類中沒找到,在 B 類的兄弟類 C 中找到了,符合要求。
3.3 重復(fù)調(diào)用問題
重復(fù)調(diào)用問題 也稱 鉆石繼承問題 或 菱形圖問題。
先來看看普通調(diào)用方法在:
>>> class A: def __init__(self): print("打印屬性 a") >>> class B(A): def __init__(self): print("打印屬性 b") A.__init__(self) >>> class C(A): def __init__(self): print("打印屬性 c") A.__init__(self) >>> class D(B, C): def __init__(self): print("打印屬性 d") B.__init__(self) C.__init__(self) >>> d = D() 打印屬性 d 打印屬性 b 打印屬性 a 打印屬性 c 打印屬性 a
- 因為 B,C 都繼承自 A,所以當(dāng) D 在實例化時,A 的構(gòu)造函數(shù)被執(zhí)行了兩次。這就是所謂的重復(fù)調(diào)用問題。
- 很顯然,我們只需要調(diào)用一次就可以了,重復(fù)的調(diào)用只會造成資源浪費。
接下來我們使用 super() 函數(shù)來調(diào)用:
>>> class A: def __init__(self): print("打印屬性 a") >>> class B(A): def __init__(self): print("打印屬性 b") super().__init__() # super() 等同于 super(B, self) >>> class C(A): def __init__(self): print("打印屬性 c") super().__init__() # super() 等同于 super(C, self) >>> class D(B, C): def __init__(self): print("打印屬性 d") super(D, self).__init__() >>> d = D() 打印屬性 d 打印屬性 b 打印屬性 c 打印屬性 a
- 查看輸出結(jié)果我們發(fā)現(xiàn)雖然解決了重復(fù)調(diào)用問題,但是輸出結(jié)果的順序好像與我們想的有所區(qū)別。我們的慣性思維是:先執(zhí)行 D 類的
__init__()
方法,接著調(diào)用 B 類的__init__()
方法,B 類的構(gòu)造方法中又調(diào)用了父類 A 的__init_()
方法,然后再是調(diào)用 C 類的__init_()
方法,該方法也調(diào)用了父類 A 的__init__()
方法。所以執(zhí)行的結(jié)果應(yīng)該是:打印屬性 d,打印屬性 b,打印屬性 a,打印屬性 c。 - 為何結(jié)果不是我們想的那樣呢,首先我們要知道 D 類中的第二個參數(shù) self 為 D 的實例 d,它提供的 MRO 為:D→B→C→A→object。所以 D 類中的
super()
函數(shù)產(chǎn)生的是 d 的代理對象,當(dāng)其調(diào)用父類 B 的__init__()
時,B 的super()
的第二個參數(shù)為 D 中的 super object,其所提供的 MRO 依舊為:D→B→C→A→object。也就是說 B 中的super()
調(diào)用的是它的上一級 C 中的__init__()
,而不是 A 中的__init__()
。所以執(zhí)行的結(jié)果是:打印屬性 d,打印屬性 b,打印屬性 c,打印屬性 a。
3.4 super(type) 問題
>>> class A: def funxx(self): print("...A...") >>> class B(A): def funxx(self): print("...B...") >>> sa = super(B) >>> print(sa) <super: <class 'B'>, NULL> >>> print(type(sa)) <class 'super'>
可以看出 super(type) 返回的是一個無效的對象,或者是未綁定的 super object。
到此這篇關(guān)于Python super( )函數(shù)用法總結(jié)的文章就介紹到這了,更多相關(guān)super( )函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Django中調(diào)用keras的模型出現(xiàn)的問題
今天小編就為大家分享一篇解決Django中調(diào)用keras的模型出現(xiàn)的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08分析python動態(tài)規(guī)劃的遞歸、非遞歸實現(xiàn)
本文小編給大家詳細(xì)分析了python動態(tài)規(guī)劃的遞歸、非遞歸實現(xiàn)過程以及相關(guān)代碼,有興趣的朋友可以學(xué)習(xí)下。2018-03-03Python數(shù)據(jù)分析之?Matplotlib?散點圖繪制
這篇文章主要介紹了Python數(shù)據(jù)分析之?Matplotlib?散點圖繪制,散點圖又稱散點圖,是使用多個坐標(biāo)點的分布反映數(shù)據(jù)點分布規(guī)律、數(shù)據(jù)關(guān)聯(lián)關(guān)系的圖表,下文對散點圖的詳細(xì)介紹及繪制,需要的小伙伴可以參考以一下2022-05-05django通過ajax發(fā)起請求返回JSON格式數(shù)據(jù)的方法
這篇文章主要介紹了django通過ajax發(fā)起請求返回JSON格式數(shù)據(jù)的方法,較為詳細(xì)的分析了django處理ajax請求的技巧,需要的朋友可以參考下2015-06-06macOS M1(Apple Silicon)安裝配置Conda環(huán)境的具體實現(xiàn)
由于常用的Anaconda和Miniconda現(xiàn)在都沒有提供M1處理器支持的conda環(huán)境,以下是conda-forge提供的miniforge,感興趣的可以了解一下2021-08-08