Logo

新人日誌

首頁關於我部落格

新人日誌

Logo

網站會不定期發佈技術筆記、職場心得相關的內容,歡迎關注本站!

網站
首頁關於我部落格
部落格
分類系列文

© 新人日誌. All rights reserved. 2020-present.

初學者指南:深入了解 Python 方法覆寫與 super()

最後更新:2024年11月18日Python

本文為 python 物件導向系列文:第五篇

  1. 深入理解 Python 中的 self 與物件導向原理
  2. 初學者指南:深入了解 Python 的 init 方法
  3. 理解 Python 中的 str 與 repr 方法
  4. 初學者指南:深入了解 Python 繼承
  5. 初學者指南:深入了解 Python 方法覆寫與 super() 👈所在位置
  6. 初學者指南:深入了解 Python 中的多重繼承與鑽石問題

在學習 Python 的物件導向程式設計(Object-Oriented Programming, OOP)時,方法覆寫(Method Overriding) 和 super() 函數 是兩個重要的概念。

方法覆寫允許子類別重新定義父類別的方法,以實現不同的行為。

super() 函數則使我們能夠在子類別中調用父類別的方法,從而擴展或修改其功能。

理解這兩個概念對於掌握 Python 的繼承機制和多型性至關重要。

本文將為新手詳細介紹 Python 中的方法覆寫與 super() 的使用,解釋其作用、如何定義和應用,以及在實際開發中的意義。


什麼是方法覆寫?

方法覆寫(Method Overriding) 是指在子類別中,定義一個與父類別同名的方法,從而取代父類別中的方法實現。

透過方法覆寫,子類別可以定制自己的行為,而不必受限於父類別的方法定義。

特點

  • 名稱相同:子類別的方法名稱與父類別的方法名稱相同。
  • 參數相同:通常,方法的參數列表也相同,確保可以被同樣地調用。
  • 實現不同:子類別的方法提供了不同的實現,以滿足特定需求。

方法覆寫的基本用法

父類別與子類別

class Animal:
    def make_sound(self):
        print("動物發出聲音")

class Dog(Animal):
    def make_sound(self):
        print("狗狗汪汪叫")

使用子類別

animal = Animal()
animal.make_sound()  # 輸出:動物發出聲音

dog = Dog()
dog.make_sound()     # 輸出:狗狗汪汪叫
  • 說明:Dog 類別繼承自 Animal,並覆寫了 make_sound 方法。

為什麼要覆寫方法?

  1. 實現多型性:透過方法覆寫,子類別可以表現出與父類別不同的行為,實現多型性。
  2. 定制化行為:子類別可以根據自己的需求,修改或擴展父類別的方法。
  3. 代碼重用:在保留父類別基本結構的同時,子類別可以重新定義部分方法,避免重複編寫代碼。

示例:多型性

class Animal:
    def make_sound(self):
        print("動物發出聲音")

class Cat(Animal):
    def make_sound(self):
        print("貓咪喵喵叫")

class Cow(Animal):
    def make_sound(self):
        print("乳牛哞哞叫")

animals = [Animal(), Cat(), Cow()]

for animal in animals:
    animal.make_sound()

輸出:

動物發出聲音
貓咪喵喵叫
乳牛哞哞叫
  • 說明:透過方法覆寫,不同的動物實體在調用 make_sound 方法時表現出不同的行為。

使用 super() 函數

當我們在子類別中覆寫了父類別的方法,但仍然希望保留父類別的方法功能時,可以使用 super() 函數來調用父類別的方法。

基本語法

class 子類別(父類別):
    def 方法名(self, 參數):
        super().方法名(參數)
        # 子類別的方法實現

示例

class Animal:
    def make_sound(self):
        print("動物發出聲音")

class Dog(Animal):
    def make_sound(self):
        super().make_sound()  # 調用父類別的方法
        print("狗狗汪汪叫")

使用子類別

dog = Dog()
dog.make_sound()

輸出:

動物發出聲音
狗狗汪汪叫
  • 說明:super().make_sound() 調用了父類別 Animal 的 make_sound 方法,然後在子類別中添加了新的行為。

延伸閱讀:初學者指南:深入了解 Python 中的多重繼承與鑽石問題


示例:覆寫與 super() 的綜合應用

定義一個帳戶類別

class Account:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def display_balance(self):
        print(f"{self.owner} 的帳戶餘額為:{self.balance} 元")

定義一個子類別,帶有透支功能

class OverdraftAccount(Account):
    def __init__(self, owner, balance=0, overdraft_limit=0):
        super().__init__(owner, balance)
        self.overdraft_limit = overdraft_limit

    def withdraw(self, amount):
        if self.balance + self.overdraft_limit >= amount:
            self.balance -= amount
            print(f"成功提取 {amount} 元,當前餘額為 {self.balance} 元")
        else:
            print("餘額不足,且超出透支限額")

說明:當我們在在子類別中定義了自己的 __init__ 方法時,該方法會覆蓋掉父類別的 __init__ 方法。

這意味著,父類別的 __init__ 方法不會自動被調用,父類別中負責初始化的代碼(如 self.owner = owner 和 self.balance = balance)也不會執行。

在子類別的 __init__ 方法中,我們有兩種選擇來初始化父類別的屬性:

選擇一:使用 super() 調用父類別的 __init__ 方法

def __init__(self, owner, balance=0, overdraft_limit=0):
    super().__init__(owner, balance)     # 調用父類別的 __init__ 方法
    self.overdraft_limit = overdraft_limit
  • 優點:
    • 避免代碼重複,直接利用父類別的初始化邏輯。
    • 如果父類別的 __init__ 方法有複雜的初始化邏輯,這種方式更可靠。

選擇二:在子類別的 __init__ 方法中手動初始化父類別的屬性

def __init__(self, owner, balance=0, overdraft_limit=0):
    self.owner = owner       # 手動初始化父類別的屬性
    self.balance = balance
    self.overdraft_limit = overdraft_limit
  • 缺點:
    • 代碼重複,如果父類別的初始化邏輯發生變化,需要在多個地方修改代碼。
    • 容易遺漏父類別中的其他初始化邏輯。

因此,如果您需要父類別中的屬性和初始化邏輯,您必須在子類別的 __init__ 方法中明確地調用父類別的 __init__ 方法。這通常透過使用 super() 函數來實現:

super().__init__(owner, balance)

小結

  • 覆蓋父類別的 __init__ 方法:子類別定義自己的 __init__ 方法後,父類別的 __init__ 方法不會自動執行。
  • 需要父類別的屬性:如果子類別需要使用父類別的屬性,必須手動調用父類別的 __init__ 方法。
  • 使用 super():透過 super().__init__(...),您可以調用父類別的 __init__ 方法,繼承並初始化父類別的屬性。

使用子類別

account = OverdraftAccount("Alice", balance=1000, overdraft_limit=500)
account.display_balance()  # 輸出:Alice 的帳戶餘額為:1000 元

account.withdraw(1200)     # 成功提取 1200 元,當前餘額為 -200 元
account.display_balance()  # 輸出:Alice 的帳戶餘額為:-200 元

account.withdraw(400)      # 餘額不足,且超出透支限額

注意事項

  1. 確保正確使用 super():在覆寫方法時,如果需要調用父類別的方法,應該使用 super(),避免直接使用父類別名稱,這有助於正確處理多重繼承。
  2. 方法覆寫時參數需一致:為了確保方法能夠被正確地調用,覆寫的方法應該與父類別的方法有相同的參數列表。
  3. 避免無限遞歸:在覆寫方法時,如果不小心調用了自身的方法,而非父類別的方法,可能會導致無限遞歸。
   class MyClass:
       def method(self):
           self.method()  # 錯誤,應該使用 super().method()

結論

方法覆寫與 super() 是 Python 物件導向程式設計中的重要概念,透過它們,我們可以:

  • 定制子類別的行為:覆寫父類別的方法,實現特定功能。
  • 重用父類別的代碼:使用 super() 調用父類別的方法,避免重複編寫代碼。
  • 實現多型性:使不同的類別對同一方法作出不同的實現,提高程式的靈活性。

理解並熟練使用方法覆寫與 super(),將有助於你更好地掌握 Python 的繼承機制,編寫出更具結構性和可維護性的程式碼。


進一步學習

  • 多重繼承與 MRO:深入研究 Python 中的多重繼承和方法解析順序。
  • 抽象類別與介面:學習如何使用 abc 模組創建抽象類別,定義介面。
  • 設計模式:學習常見的設計模式,如模板方法模式、策略模式等,提升程式設計能力。
  • 反射與元編程:瞭解如何在運行時動態地獲取和調用類別的方法。
目前還沒有留言,成為第一個留言的人吧!

發表留言

留言將在審核後顯示。

Python

目錄

  • 什麼是方法覆寫?
  • 特點
  • 方法覆寫的基本用法
  • 父類別與子類別
  • 使用子類別
  • 為什麼要覆寫方法?
  • 示例:多型性
  • 使用 super() 函數
  • 基本語法
  • 示例
  • 使用子類別
  • 示例:覆寫與 super() 的綜合應用
  • 定義一個帳戶類別
  • 定義一個子類別,帶有透支功能
  • 使用子類別
  • 注意事項
  • 結論
  • 進一步學習