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

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

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

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

  1. 為什么子類(lèi)的 __init__ 必須手動(dòng)調(diào)用父類(lèi)的 __init__?

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

本文將通過(guò)“造房子”的類(lèi)比和“鉆石問(wèn)題”的深度解析,徹底澄清這些概念。

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

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

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

  1. 先在子類(lèi)中尋找該方法。

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

  3. 如果沒(méi)找到,才去父類(lèi)中尋找。

這個(gè)規(guī)則會(huì)導(dǎo)致一個(gè)常見(jiàn)問(wèn)題:子類(lèi) __init__ 會(huì)覆蓋父類(lèi) __init__

類(lèi)比:造房子(StandardHousevsDeluxeHouse)

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

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

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

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

錯(cuò)誤的繼承(“覆蓋”導(dǎo)致的問(wèn)題)

class DeluxeHouse(StandardHouse):
    # 子類(lèi)定義了自己的 __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)用繼承來(lái)的方法
except AttributeError as e:
    print(f"\n!!! 出錯(cuò)了: {e}")

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

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

!!! 出錯(cuò)了: 'DeluxeHouse' object has no attribute 'foundation'

錯(cuò)誤分析:

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

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

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

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

  5. 當(dāng) get_info() 試圖訪(fǎng)問(wèn) self.foundation 時(shí),程序崩潰。

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

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

1.super()的含義

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

  • super().__init__(...):通過(guò)該代理對(duì)象,調(diào)用父類(lèi)的 __init__ 方法。

2.self的真相

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

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

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

正確的代碼:

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

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

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

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

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

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

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

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

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

在簡(jiǎn)單的“單繼承”場(chǎng)景下,兩者似乎都能工作:

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):
        # 語(yǔ)法:
        # 1. 不需要寫(xiě)父類(lèi)名
        # 2. 不需要傳遞 self
        super().__init__(brand)
        self.model = model

# 2. 老式方式 (父類(lèi)名)
class Car_Old(Vehicle):
    def __init__(self, brand, model):
        # 語(yǔ)法:
        # 1. 必須 明確寫(xiě)出父類(lèi)名 (Vehicle)
        # 2. 必須 手動(dòng)傳遞 self
        Vehicle.__init__(self, brand)
        self.model = model

為什么 super() 完勝?

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

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

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

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

     A
   /   \
  B     C
   \   /
     D

1.super()的正確演示

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

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

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

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

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

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

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

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

2. “老式”方法的錯(cuò)誤演示

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

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

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

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

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

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

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

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

結(jié)論與建議

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

最終建議:

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

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

相關(guān)文章

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

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

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

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

    這篇文章主要為大家詳細(xì)介紹了如何模擬Everything,即通過(guò)python+PyQt5來(lái)實(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),用于處理長(zhǎng)文本或?qū)崟r(shí)交互場(chǎng)景,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-03-03
  • Python+Qt實(shí)現(xiàn)智能應(yīng)用時(shí)長(zhǎng)統(tǒng)計(jì)工具

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

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

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

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

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

    這篇文章主要介紹了Python從函數(shù)參數(shù)類(lèi)型引出元組,結(jié)合實(shí)例形式分析了Python函數(shù)定義與使用中常見(jiàn)的三種參數(shù)類(lèi)型,并簡(jiǎn)單分析了元組類(lèi)型參數(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 格式,希望對(duì)大家有所幫助
    2026-02-02
  • Python制作簡(jiǎn)單的網(wǎng)頁(yè)爬蟲(chóng)

    Python制作簡(jiǎn)單的網(wǎng)頁(yè)爬蟲(chóng)

    自己寫(xiě)的一個(gè)爬蟲(chóng),模仿了python核心編程書(shū)里的程序,有詳細(xì)的注釋。 是我一個(gè)理解學(xué)習(xí)的過(guò)程吧。 有需要的小伙伴可以參考下
    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ī)等級(jí)考試中遇到詞頻排序的問(wèn)題,我們一般先通過(guò)生成字典的方法,統(tǒng)計(jì)詞的頻次,然后給字典排序,那么如何快速地給字典按照鍵值進(jìn)行排序呢?本文給大家介紹了Python中給字典排序的七種方法,需要的朋友可以參考下
    2025-07-07

最新評(píng)論

纳雍县| 道真| 黄大仙区| 太康县| 金堂县| 阳西县| 关岭| 哈巴河县| 苗栗市| 驻马店市| 温宿县| 静乐县| 颍上县| 吉林省| 临洮县| 福建省| 天柱县| 阿合奇县| 大足县| 方城县| 株洲县| 绥化市| 嘉义市| 会东县| 甘南县| 镇巴县| 金坛市| 沾益县| 曲沃县| 泰和县| 定南县| 临潭县| 汉沽区| 秭归县| 丰镇市| 辽源市| 丹阳市| 怀集县| 舒兰市| 无锡市| 海淀区|