Python內置函數(63)——super

来源:http://www.cnblogs.com/sesshoumaru/archive/2016/12/01/6120517.html
-Advertisement-
Play Games

英文文檔: super([type[, object-or-type]]) Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for acces ...


英文文檔:

super([type[, object-or-type]])

Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.

The __mro__ attribute of the type lists the method resolution search order used by both getattr() and super(). The attribute is dynamic and can change whenever the inheritance hierarchy is updated.

If the second argument is omitted, the super object returned is unbound. If the second argument is an object, isinstance(obj, type) must be true. If the second argument is a type, issubclass(type2, type) must be true (this is useful for classmethods).

There are two typical use cases for super. In a class hierarchy with single inheritance, super can be used to refer to parent classes without naming them explicitly, thus making the code more maintainable. This use closely parallels the use of super in other programming languages.

The second use case is to support cooperative multiple inheritance in a dynamic execution environment. This use case is unique to Python and is not found in statically compiled languages or languages that only support single inheritance. This makes it possible to implement “diamond diagrams” where multiple base classes implement the same method. Good design dictates that this method have the same calling signature in every case (because the order of calls is determined at runtime, because that order adapts to changes in the class hierarchy, and because that order can include sibling classes that are unknown prior to runtime).

Note that super() is implemented as part of the binding process for explicit dotted attribute lookups such as super().__getitem__(name). It does so by implementing its own __getattribute__() method for searching classes in a predictable order that supports cooperative multiple inheritance. Accordingly, super() is undefined for implicit lookups using statements or operators such as super()[name].

Also note that, aside from the zero argument form, super() is not limited to use inside methods. The two argument form specifies the arguments exactly and makes the appropriate references. The zero argument form only works inside a class definition, as the compiler fills in the necessary details to correctly retrieve the class being defined, as well as accessing the current instance for ordinary methods.

 

說明:

  1. super函數返回的是一個代理對象,通過此對象可以調用所在類的父類或者兄弟類的方法,而不顯示的指定父類或者兄弟類的類名。

  2. 為什麼要有super?

    最早之前,在子類(B)中調用父類(A)的方法採用的方式如下: 

#定義父類A
>>> class A(object):
    def __init__(self):
        print('A.__init__')

#實例化A        
>>> a = A() 
A.__init__

# 定義子類B,繼承A,在B的__init__ 方法中調用A的__init__方法
>>> class B(A): 
    def __init__(self):
        print('B.__init__')
        A.__init__(self)

 #實例化B
>>> b = B()
B.__init__
A.__init__

    假設現在要更改新定義一個類(A1),並更改繼承關係(B->A改成B->A1),則需要所有類中做如下修改:

#定義新的父類A1
>>> class A1(object):
    def __init__(self):
        print('A1.__init__')

#更改繼承關係B->A改成B->A1
>>> class B(A1):
    def __init__(self):
        print('B.__init__')
        A1.__init__(self)

#能正確調用新的父類A1的__init__方法
>>> b = B()
B.__init__
A1.__init__

#假設忘了修改A.__init__(self)
>>> class B(A1):
    def __init__(self):
        print('B.__init__')
        A.__init__(self)
      
#則還是調用了A的__init__方法
>>> b = B()
B.__init__
A.__init__

    引入super之後,不需要顯示指定父類的類名,增強了程式的可維護性:

#B->A 改用super方式調用父類方法
>>> class B(A):
    def __init__(self):
        print('B.__init__')
        super().__init__()

#能正確調用父類方法
>>> b = B()
B.__init__
A.__init__

#更改繼承關係B->A改成B->A1,調用父類方法方式不用修改
>>> class B(A1):
    def __init__(self):
        print('B.__init__')
        super().__init__()

#也能正確調用父類方法
>>> b = B()
B.__init__
A1.__init__

  3. 不帶任何參數的super等效於super(類名,self),此種情況多用於單繼承關係的子類中。

#super不帶參數
>>> class B(A1):
    def __init__(self):
        print('B.__init__')
        super().__init__()

#能正確調用父類方法
>>> b = B()
B.__init__
A1.__init__

#super帶兩個參數(類名,self)
>>> class B(A1):
    def __init__(self):
        print('B.__init__')
        super(B,self).__init__()

#也能正確調用父類方法
>>> b = B()
B.__init__
A1.__init__

  4. 如果第2個參數不傳入,則表示代理對象不綁定繼承關係。

#super第2個參數不傳入,生成代理對象不綁定繼承關係
>>> class B(A1):
    def __init__(self):
        print('B.__init__')
        super(B).__init__()

#super(B).__init__()方法執行時不會調用父類方法
>>> b = B()
B.__init__

  5. 如果第2個參數是一個對象,則對象必須是第1個參數指定類型的實例,此種關係多用於多層繼承關係的子類中。

#定義父類A
>>> class A(object):
    def __init__(self):
        print('A.__init__')

#定義子類B,繼承A,__init__中調用父類的__init__方法
>>> class B(A):
    def __init__(self):
        print('B.__init__')
        super().__init__()

#定義子類C,繼承B,__init__中調用父類的__init__方法        
>>> class C(B):
    def __init__(self):
        print('C.__init__')
        super().__init__()

#實例化C時,執行C的__init__方法,調用直接父類B的__init__方法,又進一步調用間接父類A的__init__方法
>>> c = C()
C.__init__
B.__init__
A.__init__

#重新定義子類C,繼承關係不變,調用父類方法__init__時改用super(B,self)
>>> class C(B):
    def __init__(self):
        print('C.__init__')
        super(B,self).__init__()

#實例化C時,執行C的__init__方法,super(B,self)代理找到B的父類A,將self轉換成B的實例,直接調用了A的__init__方法,跳過了調用B的__init__方法
>>> c = C()
C.__init__
A.__init__

#定義一個新類D
>>> class D(object):
    def __init__(self):
        print('D.__init__')

#重新定義C,繼承關係不變,調用父類方法__init__時改用super(D,self)
>>> class C(B):
    def __init__(self):
        print('C.__init__')
        super(D,self).__init__()

#實例化C時,執行C的__init__方法,super(D,self)代理找到D的父類object,將self轉換成D的實例,因為D和C無繼承關係,self
無法轉換成D的實例所以報錯
>>> c= C()
C.__init__
Traceback (most recent call last):
  File "<pyshell#14>", line 1, in <module>
    c= C()
  File "<pyshell#13>", line 4, in __init__
    super(D,self).__init__()
TypeError: super(type, obj): obj must be an instance or subtype of type

  6. 如果第2個參數時一個類型,則類型必須是第1個參數指定類型的子類,此種關係多用於多層繼承關係的子類中,適用於類方法。

#定義父類A,並定義有一個類方法sayHello
>>> class A(object):
    @classmethod
    def sayHello(cls):
        print('A.sayHello')

# 定義子類B,繼承A,重寫類方法sayHello,在其中調用父類的sayHello方法
>>> class B(A):
    @classmethod
    def sayHello(cls):
        print('B.sayHello')
        super().sayHello()

# 定義子類C,繼承B,重寫類方法sayHello,在其中調用父類的sayHello方法
>>> class C(B):
    @classmethod
    def sayHello(cls):
        print('C.sayHello')
        super().sayHello()

#調用C的類方法sayHello,其調用C的直接父類B的類方法sayHello,調用時B的sayHello方法又調用B的直接父類A的類方法sayHello
>>> C.sayHello()
C.sayHello
B.sayHello
A.sayHello

#重新定義類C,繼承關係不變,使用super(C,C)的方式調用父類方法
>>> class C(B):
    @classmethod
    def sayHello(cls):
        print('C.sayHello')
        super(C,C).sayHello()

#調用C的類方法sayHello,super(C,C)代理對象,找到C的直接父類B,然後調用C的直接父類B的類方法sayHello,調用時B的sayHello方法又調用B的直接父類A的類方法sayHello
>>> C.sayHello()
C.sayHello
B.sayHello
A.sayHello

#重新定義類C,繼承關係不變,使用super(B,C)的方式調用父類方法
>>> class C(B):
    @classmethod
    def sayHello(cls):
        print('C.sayHello')
        super(B,C).sayHello()

#調用C的類方法sayHello,super(B,C)代理對象,找到B的直接父類A,然後調用B的直接父類A的類方法sayHello,中間不會調用B的sayHello方法
>>> C.sayHello()
C.sayHello
A.sayHello

#定義一個新類D,和A、B、C無繼承關係
>>> class D(object):
    @classmethod
    def sayHello(cls):
        print('D.sayHello')

#重新定義類C,繼承關係不變,使用super(D,C)的方式調用父類方法
>>> class C(B):
    @classmethod
    def sayHello(cls):
        print('C.sayHello')
        super(D,C).sayHello()

#調用C的類方法sayHello,super(D,C)代理對象,找到B的直接父類object,然後將C轉換成D類,轉換失敗調用出錯
>>> C.sayHello()
C.sayHello
Traceback (most recent call last):
  File "<pyshell#81>", line 1, in <module>
    C.sayHello()
  File "<pyshell#80>", line 5, in sayHello
    super(D,C).sayHello()
TypeError: super(type, obj): obj must be an instance or subtype of type

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 上個月月底,VS2017RC版發佈了,一個很大的特點就是將原來的xProj文件又改回了csproj了。 這樣一改,其實很多新的問題也暴露出來了,最嚴重的問題就是Net版本相容性。 原來的Net體系大致是NetFramework,Net Core這樣的,雖然也有Net Standard 這樣的概念,但 ...
  • 本隨筆續接:.NET 實現並行的幾種方式(三) 八、await、async - 非同步方法的秘密武器 1) 使用async修飾符 和 await運算符 輕易實現非同步方法 前三篇隨筆已經介紹了多種方式、利用多線程、充分利用多核心CPU以提高運行效率。但是以前的方式在WebAPI和GUI系統上、 使用起來 ...
  • 用法一、this代表當前實例,用this.來調用當前實例的成員方法,變數,屬性,欄位等 ...
  • 官方資料: "https://github.com/dotnet/core" "https://docs.microsoft.com/en us/aspnet/core" "https://docs.microsoft.com/en us/ef/core" 相關文章: "ASP.NET 5 RC1 ...
  • 本節從三個角度簡要總結之前介紹的各種容器類:用法和特點,數據結構和演算法,設計思維和模式。 ...
  • 一.簡介 pymsql是Python中操作MySQL的模塊,其使用方法和MySQLdb幾乎相同,但目前pymysql支持python3.x而後者不支持3.x版本 其執行語句與sql源碼相似 二.使用 1.安裝 pip install pymysql 2.使用操作 先來一例完整的連接加基本的操作 向數 ...
  • 這裡先從元素是否有序,按照什麼順序來應用進行Set的選擇,最後再從線程安全的角度說一下Set的選擇。 ...
  • #include<stdio.h>#include<stdlib.h>//此鏈表中的數據均為int型typedef struct Link_list{ int date; struct Link_list *next;}Link; int main(){ Link *Link_creat(); vo ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...