在 Python 的面向對象編程(OOP)中,繼承(Inheritance) 是一種重要的機制,它允許一個類(稱為子類或派生類)從另一個類(稱為父類、基類或超類)中繼承屬性和方法。
為什么需要繼承
考慮我們之前定義的 Person
類,現在我們想創建 Student
和 Teacher
類。它們都屬于“人”,所以都有姓名和年齡。
# 傳統的做法,沒有繼承
class Person:def __init__(self, name, age):self.name = nameself.age = agedef introduce(self):print(f"大家好,我叫 {self.name},今年 {self.age} 歲。")class Student:def __init__(self, name, age, student_id):# 代碼重復self.name = name# 代碼重復self.age = age self.student_id = student_iddef introduce(self):# 代碼重復print(f"大家好,我叫 {self.name},今年 {self.age} 歲。")print(f"我的學號是 {self.student_id}。")class Teacher:def __init__(self, name, age, subject):# 代碼重復self.name = name# 代碼重復self.age = age self.subject = subjectdef introduce(self):# 代碼重復print(f"大家好,我叫 {self.name},今年 {self.age} 歲。")print(f"我教 {self.subject}。")
你會發現 name
、age
屬性以及 introduce
方法在 Person
、Student
和 Teacher
類中重復出現了。這種代碼重復會導致:
- 維護困難: 如果你需要修改“人”的共同行為(比如
introduce
方法),你必須在所有相關的類中都修改一遍。 - 擴展性差: 每增加一個新的“人”的角色(比如
Employee
),你都要重新編寫這些通用部分。
繼承就是為了解決這些問題: 它允許你定義一個通用的父類,把共同的屬性和方法放在父類中。然后,特定的子類可以繼承這些共同部分,并添加自己獨有的屬性和方法,或者修改(重寫)父類的行為。
繼承的基本用法
在 Python 中,子類在定義時,在類名后面的括號中指定它所繼承的父類。
class ChildClass(ParentClass, OtherParentClass):
示例:Person
、Student
和 Teacher
的繼承關系
class Person:species = "人類" # 類屬性def __init__(self, name, age):self.name = nameself.age = ageprint(f"創建了一個 Person 對象: {self.name}")def introduce(self):print(f"大家好,我叫 {self.name},今年 {self.age} 歲,是 {self.species}。")def celebrate_birthday(self):self.age += 1print(f"{self.name} 過生日了,現在 {self.age} 歲了!")# Student 繼承自 Person
class Student(Person):def __init__(self, name, age, student_id):# 調用父類 (Person) 的構造器來初始化共同屬性super().__init__(name, age)# Student 獨有的屬性self.student_id = student_idprint(f"創建了一個 Student 對象: {self.name}, 學號: {self.student_id}")# 重寫 (Override) 父類的 introduce 方法def introduce(self):# 調用父類的 introduce 方法,重用其邏輯super().introduce()print(f"我的學號是 {self.student_id}。")def study(self):# Student 獨有的方法print(f"{self.name} 正在努力學習。")# Teacher 繼承自 Person
class Teacher(Person):def __init__(self, name, age, subject):# 調用父類 (Person) 的構造器super().__init__(name, age)# Teacher 獨有的屬性self.subject = subject print(f"創建了一個 Teacher 對象: {self.name}, 教授: {self.subject}")# 重寫父類的 introduce 方法def introduce(self):# 重用父類的 introduce 邏輯super().introduce()print(f"我教 {self.subject}。")def teach(self):# Teacher 獨有的方法print(f"{self.name} 正在教 {self.subject}。")# --- 演示與測試 ---
print("--- 創建對象 ---")
person = Person("王五", 40)
student = Student("小明", 18, "S12345")
teacher = Teacher("李老師", 35, "數學")print("\n--- 調用方法 ---")
person.introduce()
person.celebrate_birthday()student.introduce()
student.study()
# 繼承自 Person
student.celebrate_birthday()teacher.introduce()
teacher.teach()
# 繼承自 Person
teacher.celebrate_birthday()
在 Python 中,子類默認會繼承父類的所有屬性和方法。如果你想讓父類的某個屬性不被繼承,可以通過使用 __ 前綴創建私有屬性。
class Parent:# 這是一個私有屬性,子類無法直接訪問__private_property = "這是父類的私有屬性"def __init__(self):# 這是一個私有實例屬性self.__private_instance_property = "這是父類的私有實例屬性"def get_private_property(self):# 通過方法返回私有屬性print(self.__private_property)print(self.__private_instance_property)class Child(Parent):def __init__(self):# 調用父類的構造函數super().__init__()print("嘗試從子類訪問父類的私有屬性:")try:# 嘗試訪問父類的私有屬性,會引發 AttributeErrorprint(self.__private_instance_property)except AttributeError as e:print(f" 錯誤:{e}")# 創建子類實例
child_obj = Child()
# 嘗試從外部訪問父類的私有屬性,也會引發 AttributeError
try:print(child_obj.__private_instance_property)
except AttributeError as e:print(f" 外部訪問錯誤:{e}")print("\n通過父類方法訪問:")
# 通過父類的方法可以成功訪問
child_obj.get_private_property()
super()
函數
在子類中,我們經常需要調用父類的方法,特別是父類的構造器 __init__()
。這時,我們使用內置的 super()
函數。
super().__init__(...)
: 調用父類的__init__
方法來初始化父類定義的屬性。這是一種推薦的做法,確保父類的初始化邏輯得到執行。super().method_name(...)
: 調用父類的其他方法。這在子類重寫了父類方法后,仍想在子類中執行父類的原始邏輯時非常有用。
:::warning
在 Python 3 中,super()
函數不帶參數就可以自動獲取當前類和實例,所以直接寫 super().__init__(...)
即可。在 Python 2 中,可能需要寫成 super(ChildClass, self).__init__(...)
。
:::
方法重寫
當子類中定義了一個與父類中同名的方法時,子類的方法會**覆蓋(override)**父類的方法。這意味著當你通過子類的實例調用該方法時,會執行子類中定義的方法。
在上面的示例中,Student
和 Teacher
類都重寫了 Person
類的 introduce
方法。重寫時,它們還通過 super().introduce()
調用了父類的 introduce
方法,以在添加自己特有信息的同時,保留父類的通用介紹。
多重繼承
Python 允許一個子類繼承多個父類,這被稱為多重繼承。
語法如下:
class ChildClass(Parent1, Parent2, ...):
當一個子類繼承了多個父類,并且這些父類中有同名的方法或屬性時,Python 會遵循**方法解析順序(Method Resolution Order, MRO)**來查找方法或屬性。你可以通過 ChildClass.__mro__
屬性或 help(ChildClass)
來查看 MRO。
:::warning
在 Python 中,MRO(Method Resolution Order,方法解析順序) 是一個決定多重繼承下方法或屬性查找順序的規則。它采用 C3 線性化算法 計算,確保類繼承關系的一致性和可預測性。
:::
class Flying:def fly(self):print("I can fly!")class Swimming:def swim(self):print("I can swim!")# 鴨子既能飛又能游
class Duck(Flying, Swimming):def quack(self):print("Quack! Quack!")duck = Duck()
duck.fly()
duck.swim()
duck.quack()print(Duck.__mro__) # 查看方法解析順序
:::warning
多重繼承雖然強大,但也可能導致復雜的繼承關系和“菱形繼承問題”(diamond problem)。在使用時需要謹慎,并理解 MRO。
:::