最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

理解Python繼承之從__init__覆蓋到super()的妙用方法

 更新時間:2025年12月01日 08:32:28   作者:雨夜的星光  
這篇文章主要介紹了理解Python繼承之從__init__覆蓋到super()的相關(guān)資料,解決了初學(xué)者對為何子類的__init__必須手動調(diào)用父類__init__的困惑,需要的朋友可以參考下

Python的面向?qū)ο缶幊蹋∣OP)中,繼承是一個強(qiáng)大的工具,但它也常常是初學(xué)者(甚至有經(jīng)驗(yàn)的開發(fā)者)的困惑之源。核心的困惑點(diǎn)通常圍繞:

  1. 為什么子類的 __init__ 必須手動調(diào)用父類的 __init__?

  2. super() 到底是什么,它和直接用父類名調(diào)用有何區(qū)別?

本文將通過“造房子”的類比和“鉆石問題”的深度解析,徹底澄清這些概念。

第1部分:核心問題——__init__的“覆蓋”機(jī)制

要理解為何需要 super(),首先必須理解Python的方法搜索規(guī)則。

當(dāng)在子類實(shí)例上調(diào)用一個方法時(如 __init__),Python的搜索順序是:

  1. 先在子類中尋找該方法。

  2. 如果找到了,立即停止搜索并執(zhí)行。

  3. 如果沒找到,才去父類中尋找。

這個規(guī)則會導(dǎo)致一個常見問題:子類 __init__ 會覆蓋父類 __init__。

類比:造房子(StandardHousevsDeluxeHouse)

假設(shè)我們有一個“標(biāo)準(zhǔn)房子”的設(shè)計(jì)圖(父類):

class StandardHouse:
    def __init__(self, foundation_type):
        # 建造房子的第一步:打地基
        self.foundation = foundation_type
        print(f"地基已打好,類型是: {self.foundation}")

    def get_info(self):
        print(f"這是一座標(biāo)準(zhǔn)房子,地基是 {self.foundation}")

現(xiàn)在,我們想設(shè)計(jì)一個“豪華房子”(子類),它在“標(biāo)準(zhǔn)房子”的基礎(chǔ)上,還想額外添加一個“游泳池”。為此,我們必須定義它自己的 __init__

錯誤的繼承(“覆蓋”導(dǎo)致的問題)

class DeluxeHouse(StandardHouse):
    # 子類定義了自己的 __init__
    def __init__(self, pool_size):
        # 建造房子的第一步:建游泳池
        self.pool = pool_size
        print(f"游泳池已建好,大小是: {self.pool} 平米")

# --- 嘗試建造 ---
print("--- 準(zhǔn)備建造豪華房子 ---")
my_deluxe_house = DeluxeHouse(50)

# --- 嘗試獲取信息 ---
try:
    my_deluxe_house.get_info()  # 調(diào)用繼承來的方法
except AttributeError as e:
    print(f"\n!!! 出錯了: {e}")

執(zhí)行結(jié)果:

--- 準(zhǔn)備建造豪華房子 ---
游泳池已建好,大小是: 50 平米

!!! 出錯了: 'DeluxeHouse' object has no attribute 'foundation'

錯誤分析:

  1. 創(chuàng)建 DeluxeHouse(50) 時,Python 在 DeluxeHouse 中找到了 __init__。

  2. 立刻停止搜索,并執(zhí)行了子類的 __init__。

  3. 父類 StandardHouse 的 __init__ 從未被調(diào)用。

  4. 因此,self.foundation(地基)這個屬性根本沒有被創(chuàng)建。

  5. 當(dāng) get_info() 試圖訪問 self.foundation 時,程序崩潰。

第2部分:解決方案——super()與self的真相

DeluxeHouse 的建造者在建游泳池之前,必須顯式地(手動地)先去執(zhí)行“標(biāo)準(zhǔn)房子”的建造流程(打地基)。super() 就是這個“手動調(diào)用父類”的命令。

1.super()的含義

  • super():一個特殊的函數(shù),返回一個“父類”的代理對象。

  • super().__init__(...):通過該代理對象,調(diào)用父類的 __init__ 方法。

2.self的真相

從始至終,只有一個 self 對象。self 就是那個“正在被建造的實(shí)例”。

  • StandardHouse 的建造隊(duì)(父類)和 DeluxeHouse 的建造隊(duì)(子類)都在同一棟房子(self)上施工。

  • super() 就是子類團(tuán)隊(duì)用來“呼叫”父類團(tuán)隊(duì)的電話。

正確的代碼:

class DeluxeHouse(StandardHouse):
    # 子類 __init__ 必須接收 *所有* 參數(shù)(父類的 + 自己的)
    def __init__(self, foundation_type, pool_size):
        print("--- [子類] DeluxeHouse.__init__ 開始 ---")
        
        # 關(guān)鍵步驟:呼叫父類團(tuán)隊(duì),先把地基打好
        # 把屬于父類的參數(shù) (foundation_type) 傳遞過去
        super().__init__(foundation_type)
        
        print("--- [子類] 父類工作已完成,現(xiàn)在我來添加新功能 ---")
        # 2. 子類現(xiàn)在可以安全地設(shè)置自己的屬性
        self.pool = pool_size
        print(f"    [子類] 游泳池已建好: {self.pool}")
        print("--- [子類] DeluxeHouse.__init__ 結(jié)束 ---")

# --- 嘗試建造 ---
my_deluxe_house = DeluxeHouse("鋼筋混凝土", 50)
my_deluxe_house.get_info()

執(zhí)行流程分析:

  1. 調(diào)用 DeluxeHouse(...),進(jìn)入 DeluxeHouse.__init__。

  2. 執(zhí)行 super().__init__(...),暫停子類 __init__跳轉(zhuǎn)到父類 StandardHouse.__init__。

  3. 父類 __init__同一個 self 上設(shè)置了 self.foundation

  4. 父類 __init__ 結(jié)束,返回到子類 __init__

  5. 子類 __init__ 繼續(xù)執(zhí)行,在同一個 self 上設(shè)置 self.pool

  6. self 對象現(xiàn)在同時擁有了 .foundation.pool。

第3部分:super()vsParentClass.__init__(新舊對比)

既然必須手動調(diào)用父類,有兩種方法可以做到:

  1. 現(xiàn)代方式 (推薦): super().__init__(...)

  2. 老式方式 (不推薦): ParentClass.__init__(self, ...)

在簡單的“單繼承”場景下,兩者似乎都能工作:

class Vehicle:
    def __init__(self, brand):
        print(f"[Vehicle] 設(shè)置品牌為: {brand}")
        self.brand = brand

# 1. 現(xiàn)代方式 (super)
class Car_Modern(Vehicle):
    def __init__(self, brand, model):
        # 語法:
        # 1. 不需要寫父類名
        # 2. 不需要傳遞 self
        super().__init__(brand)
        self.model = model

# 2. 老式方式 (父類名)
class Car_Old(Vehicle):
    def __init__(self, brand, model):
        # 語法:
        # 1. 必須 明確寫出父類名 (Vehicle)
        # 2. 必須 手動傳遞 self
        Vehicle.__init__(self, brand)
        self.model = model

為什么 super() 完勝?

特性super().__init__(...) (現(xiàn)代)ParentClass.__init__(self, ...) (老式)
self 參數(shù)隱式傳遞。Python自動處理,代碼更簡潔。必須手動傳遞。容易忘記,導(dǎo)致錯誤。
可維護(hù)性高 (靈活)低 (死板 / 易碎)
原因如果父類改名 (如 Vehicle -> BaseVehicle),子類代碼無需任何改動。如果父類改名,你必須在所有子類中搜索并替換 Vehicle.__init__。
多重繼承唯一正確的方案。完全失效或?qū)е聻?zāi)難性bug。

第4部分:決定性因素——多重繼承與“鉆石問題”

super() 存在的真正理由是:它能智能地處理復(fù)雜的多重繼承,而“父類名”調(diào)用則會徹底失敗。

經(jīng)典的“鉆石問題”D 繼承自 BC,而 BC 都繼承自 A。

     A
   /   \
  B     C
   \   /
     D

1.super()的正確演示

super() 會智能地遵循“方法解析順序”(MRO),確保繼承鏈中的每個 __init__ 都被調(diào)用一次,且僅被調(diào)用一次。

class A:
    def __init__(self):
        print("A 初始化 (只應(yīng)被調(diào)用一次)")

class B(A):
    def __init__(self):
        print("B 初始化開始...")
        super().__init__()
        print("B 初始化結(jié)束。")

class C(A):
    def __init__(self):
        print("C 初始化開始...")
        super().__init__()
        print("C 初始化結(jié)束。")

class D_Super(B, C): # 孫子 (使用 super)
    def __init__(self):
        print("D_Super 初始化開始...")
        super().__init__()
        print("D_Super 初始化結(jié)束。")

print("--- 測試 super() 的多重繼承 ---")
d1 = D_Super()

super() 的正確執(zhí)行結(jié)果 (A只調(diào)用一次):

--- 測試 super() 的多重繼承 ---
D_Super 初始化開始...
B 初始化開始...
C 初始化開始...
A 初始化 (只應(yīng)被調(diào)用一次)
C 初始化結(jié)束。
B 初始化結(jié)束。
D_Super 初始化結(jié)束。

2. “老式”方法的錯誤演示

如果 BC 使用“父類名”的方式調(diào)用 A

class B_Old(A):
    def __init__(self):
        print("B_Old 初始化開始...")
        A.__init__(self) # 明確調(diào)用 A
        print("B_Old 初始化結(jié)束。")

class C_Old(A):
    def __init__(self):
        print("C_Old 初始化開始...")
        A.__init__(self) # 明確調(diào)用 A
        print("C_Old 初始化結(jié)束。")

class D_Old(B_Old, C_Old):
    def __init__(self):
        print("D_Old 初始化開始...")
        B_Old.__init__(self) # 明確調(diào)用 B
        C_Old.__init__(self) # 明確調(diào)用 C
        print("D_Old 初始化結(jié)束。")

print("\n--- 測試 '父類名' 的多重繼承 (錯誤演示) ---")
d2 = D_Old()

“老式”方法的錯誤執(zhí)行結(jié)果 (A被調(diào)用兩次!):

--- 測試 '父類名' 的多重繼承 (錯誤演示) ---
D_Old 初始化開始...
B_Old 初始化開始...
A 初始化 (只應(yīng)被調(diào)用一次)  <-- A 被調(diào)用了第1次
B_Old 初始化結(jié)束。
C_Old 初始化開始...
A 初始化 (只應(yīng)被調(diào)用一次)  <-- A 被調(diào)用了第2次 (!! BUG !!)
C_Old 初始化結(jié)束。
D_Old 初始化結(jié)束。

分析A (頂層父類) 的 __init__調(diào)用了兩次!如果 A__init__ 是在打開一個文件或建立一個數(shù)據(jù)庫連接,這種重復(fù)調(diào)用很可能會導(dǎo)致資源沖突或數(shù)據(jù)損壞。

結(jié)論與建議

對比項(xiàng)super() (推薦)ParentClass.__init__(self, ...) (不推薦)
簡單繼承可用可用(但不推薦)
多重繼承完美工作導(dǎo)致Bug(如重復(fù)調(diào)用)
可維護(hù)性 (父類改名不影響子類) (父類改名必須重構(gòu)所有子類)
語法簡潔 (自動處理self)繁瑣 (必須手動傳遞self)
適用范圍現(xiàn)代Python (3.x) 的標(biāo)準(zhǔn)歷史遺留 (Python 2 舊代碼)

最終建議:

始終使用 super()。 它更簡潔、更靈活,是唯一能正確處理復(fù)雜繼承(多重繼承)的工具。ParentClass.__init__ 是一種需要被理解(以便能看懂舊代碼)但不再需要被使用的歷史寫法。

到此這篇關(guān)于理解Python繼承之從__init__覆蓋到super()的妙用方法的文章就介紹到這了,更多相關(guān)Python繼承__init__覆蓋super()內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python列表倒序的幾種方法(切片、reverse()、reversed())

    python列表倒序的幾種方法(切片、reverse()、reversed())

    本文主要介紹了python列表倒序的幾種方法(切片、reverse()、reversed()),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Python+PyQt5來實(shí)現(xiàn)文件高速查找

    Python+PyQt5來實(shí)現(xiàn)文件高速查找

    這篇文章主要為大家詳細(xì)介紹了如何模擬Everything,即通過python+PyQt5來實(shí)現(xiàn)可視化文件的高速查找,文中的示例代碼講解詳細(xì),需要的可以參考一下
    2023-07-07
  • Python調(diào)用AnythingLLM API使用流輸出的實(shí)現(xiàn)

    Python調(diào)用AnythingLLM API使用流輸出的實(shí)現(xiàn)

    本文主要介紹了Python調(diào)用AnythingLLM API使用流輸出的實(shí)現(xiàn),用于處理長文本或?qū)崟r交互場景,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-03-03
  • Python+Qt實(shí)現(xiàn)智能應(yīng)用時長統(tǒng)計(jì)工具

    Python+Qt實(shí)現(xiàn)智能應(yīng)用時長統(tǒng)計(jì)工具

    在數(shù)字化生活日益普及的今天,我們每天與各種應(yīng)用程序的交互時間越來越長,但你是否真正了解自己的數(shù)字生活習(xí)慣,下面我們就來使用Python和Qt打造智能應(yīng)用時長統(tǒng)計(jì)工具吧
    2025-06-06
  • Python實(shí)現(xiàn)文件基本操作(打開、讀寫、關(guān)閉)的完整指南

    Python實(shí)現(xiàn)文件基本操作(打開、讀寫、關(guān)閉)的完整指南

    這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)文件基本操作的相關(guān)知識,包括文件打開,讀寫,關(guān)閉等功能,w文中的示例代碼講解詳細(xì),有需要的小伙伴可以了解下
    2026-03-03
  • Python從函數(shù)參數(shù)類型引出元組實(shí)例分析

    Python從函數(shù)參數(shù)類型引出元組實(shí)例分析

    這篇文章主要介紹了Python從函數(shù)參數(shù)類型引出元組,結(jié)合實(shí)例形式分析了Python函數(shù)定義與使用中常見的三種參數(shù)類型,并簡單分析了元組類型參數(shù)的使用,需要的朋友可以參考下
    2019-05-05
  • 使用Python實(shí)現(xiàn)將CSV轉(zhuǎn)換為XML格式

    使用Python實(shí)現(xiàn)將CSV轉(zhuǎn)換為XML格式

    如果你需要快速實(shí)現(xiàn) CSV 到 XML 的格式轉(zhuǎn)換,本文將為大家詳細(xì)介紹一下如何使用Free Spire.XLS for Python實(shí)現(xiàn) CSV 轉(zhuǎn) XML 格式,希望對大家有所幫助
    2026-02-02
  • Python制作簡單的網(wǎng)頁爬蟲

    Python制作簡單的網(wǎng)頁爬蟲

    自己寫的一個爬蟲,模仿了python核心編程書里的程序,有詳細(xì)的注釋。 是我一個理解學(xué)習(xí)的過程吧。 有需要的小伙伴可以參考下
    2015-11-11
  • python如何設(shè)置靜態(tài)變量

    python如何設(shè)置靜態(tài)變量

    在本篇內(nèi)容里小編給大家整理的是一篇關(guān)于python如何設(shè)置靜態(tài)變量的相關(guān)文章,有興趣的朋友們可以參考下。
    2020-09-09
  • Python中給字典排序的七種方法詳解

    Python中給字典排序的七種方法詳解

    我們經(jīng)常在計(jì)算機(jī)等級考試中遇到詞頻排序的問題,我們一般先通過生成字典的方法,統(tǒng)計(jì)詞的頻次,然后給字典排序,那么如何快速地給字典按照鍵值進(jìn)行排序呢?本文給大家介紹了Python中給字典排序的七種方法,需要的朋友可以參考下
    2025-07-07

最新評論

日喀则市| 海晏县| 洛南县| 勐海县| 施秉县| 宝山区| 平江县| 双桥区| 辽中县| 武陟县| 宜春市| 昌平区| 赤城县| 安新县| 怀柔区| 永兴县| 石台县| 德庆县| 永康市| 青阳县| 虞城县| 额尔古纳市| 渭源县| 扎囊县| 电白县| 侯马市| 宜良县| 临高县| 天台县| 格尔木市| 台北县| 屯昌县| 承德县| 武夷山市| 锡林浩特市| 平利县| 镇江市| 米易县| 廊坊市| 平湖市| 仪陇县|