本文為 python 物件導向系列文:第五篇
- 深入理解 Python 中的 self 與物件導向原理
- 初學者指南:深入了解 Python 的 init 方法
- 理解 Python 中的 str 與 repr 方法
- 初學者指南:深入了解 Python 繼承
- 初學者指南:深入了解 Python 方法覆寫與 super() 👈所在位置
- 初學者指南:深入了解 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方法。
為什麼要覆寫方法?
- 實現多型性:透過方法覆寫,子類別可以表現出與父類別不同的行為,實現多型性。
- 定制化行為:子類別可以根據自己的需求,修改或擴展父類別的方法。
- 代碼重用:在保留父類別基本結構的同時,子類別可以重新定義部分方法,避免重複編寫代碼。
示例:多型性
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) # 餘額不足,且超出透支限額注意事項
- 確保正確使用
super():在覆寫方法時,如果需要調用父類別的方法,應該使用super(),避免直接使用父類別名稱,這有助於正確處理多重繼承。 - 方法覆寫時參數需一致:為了確保方法能夠被正確地調用,覆寫的方法應該與父類別的方法有相同的參數列表。
- 避免無限遞歸:在覆寫方法時,如果不小心調用了自身的方法,而非父類別的方法,可能會導致無限遞歸。
class MyClass:
def method(self):
self.method() # 錯誤,應該使用 super().method()結論
方法覆寫與 super() 是 Python 物件導向程式設計中的重要概念,透過它們,我們可以:
- 定制子類別的行為:覆寫父類別的方法,實現特定功能。
- 重用父類別的代碼:使用
super()調用父類別的方法,避免重複編寫代碼。 - 實現多型性:使不同的類別對同一方法作出不同的實現,提高程式的靈活性。
理解並熟練使用方法覆寫與 super(),將有助於你更好地掌握 Python 的繼承機制,編寫出更具結構性和可維護性的程式碼。
進一步學習
- 多重繼承與 MRO:深入研究 Python 中的多重繼承和方法解析順序。
- 抽象類別與介面:學習如何使用
abc模組創建抽象類別,定義介面。 - 設計模式:學習常見的設計模式,如模板方法模式、策略模式等,提升程式設計能力。
- 反射與元編程:瞭解如何在運行時動態地獲取和調用類別的方法。