繼承是什么
繼承是面向對象編程(OOP)中的一個核心概念。繼承允許一個類(稱為子類或派生類)從另一個類(稱為父類或基類)繼承屬性和方法。這樣可以重用代碼,提高代碼的模塊化和可維護性。
- 父類(基類):提供屬性和方法的類。
- 子類(派生類):繼承父類的屬性和方法的類。
語法:
class 父類:
? ? # 父類的屬性和方法
? ? def __init__(self, 屬性1):
? ? ? ? self.屬性1 = 屬性1? ? def 方法1(self):
? ? ? ? print("這是父類的方法")
class 子類(父類):
? ? # 子類的屬性和方法
? ? def __init__(self, 屬性1, 屬性2):
? ? ? ? super().__init__(屬性1)
? ? ? ? self.屬性2 = 屬性2? ? def 方法2(self):
? ? ? ? print("這是子類的方法")
?
示例:
# 定義父類-動物
class Animal:def __init__(self, name):self.name = name# 定義一個空的方法,方法的具體實現由之類重寫def speak(self):pass# 定義一個普通方法,子類繼承該方法def eat(self):print(f"{self.name} 正在吃飯")# 定義子類-狗
class Dog(Animal):def speak(self):return f"{self.name} 汪汪叫!"# 定義子類-貓
class Cat(Animal):def speak(self):return f"{self.name} 喵喵叫!"# 創建對象并調用方法
dog = Dog("狗")
cat = Cat("貓")print(dog.speak()) # 輸出: 狗 汪汪叫!
print(cat.speak()) # 輸出: 貓 喵喵叫!dog.eat() # 輸出: 狗 正在吃飯
cat.eat() # 輸出: 貓 正在吃飯
繼承的優點
- 代碼重用:子類可以重用父類中的代碼,減少重復代碼。
- 模塊化:通過繼承,可以將通用的功能放在父類中,實現代碼模塊化。
- 可擴展性:可以在子類中添加新的功能,而不必修改父類的代碼。
多繼承
- 單繼承指的是一個類只繼承一個父類。子類可以重用父類的屬性和方法。
- 多繼承指的是一個類可以繼承多個父類,從而獲得所有父類的屬性和方法。這在某些情況下非常有用,但也可能導致復雜性增加,比如遇到方法解析順序(MRO)問題。
方法解析順序(MRO)
在多繼承中,方法解析順序(Method Resolution Order,MRO)決定了在類層次結構中搜索方法和屬性的順序。Python使用C3線性化算法來計算MRO。可以使用__mro__屬性或mro()方法來查看類的MRO。
示例:
在這個例子中,D類繼承了B和C類,而B和C類又繼承了A類。調用d.method()時,按照MRO的順序,會調用B類的method方法,因為在MRO中B類在C類之前。(繼承關系就近原則,D離B最近然后是C然后是A)。
class A:def method(self):print("A method")class B(A):def method(self):print("B method")class C(A):def method(self):print("C method")class D(B, C):passd = D()
d.method() # 輸出: B method
print(D.__mro__) # 輸出: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
子類重寫父類的方法和屬性
在Python中,子類可以重寫父類的同名方法和屬性。這意味著子類可以提供自己的實現來覆蓋父類中的方法和屬性。這樣可以使得子類具有獨特的行為,同時保留與父類的接口一致性。
- 重寫方法:當子類重寫父類的方法時,子類的方法會覆蓋父類的方法。在調用該方法時,將執行子類的實現。
- 重寫屬性:當子類重寫父類的屬性時,子類中的屬性將覆蓋父類中的同名屬性。
super() 函數
有時子類需要在重寫方法或屬性時保留對父類實現的調用。可以使用?super()?函數來調用父類的方法。
示例:
# 父類
class Parent:def greet(self):return "父類"# 子類
class Child(Parent):def greet(self):# 帶參數的寫法,寫法一# parent_greeting = super(Child, self).greet()# 不帶參數的寫法,寫法二parent_greeting = super().greet()return f"{parent_greeting} 和 子類"child = Child()
print(child.greet()) # 輸出: 父類 和 子類
重寫和重載
-
重寫
重寫指的是子類重新定義父類中的方法或屬性。通過重寫,子類可以提供自己的實現來替換父類的實現。重寫主要用于多態性和定制子類行為。
-
重載?
重載指的是在同一個作用域中定義多個具有相同名字但參數不同的方法。在許多編程語言中(例如C++和Java),重載是允許的,編譯器會根據方法簽名(參數的數量和類型)來區分它們。然而,在Python中,方法重載并不直接支持。Python中的函數或方法如果使用相同的名字,后面的定義會覆蓋前面的定義。
盡管如此,Python可以通過默認參數和可變參數來實現類似重載的效果。
私有權限
在Python中,私有權限(Private Access)用于限制類屬性和方法的訪問,即私有屬性和私有方法。使其只能在類內部使用。這是通過命名約定和名稱改寫(name mangling)機制來實現的。
_ 單下劃線 (受保護)
單下劃線前綴表示“受保護的”變量或方法。這是一種約定,表示這些變量或方法不應該不推薦在類外部直接使用,雖然它們仍然可以被訪問。
示例:
class Hello:def __init__(self):self._protected_var = "我是受保護的屬性"def _protected_method(self):return "我是受保護的方法"hello = Hello()
# 依然可以訪問到,但是不推薦不應該訪問
print(hello._protected_var) # 輸出:我是受保護的屬性
print(hello._protected_method()) # 輸出:我是受保護的方法
__ 雙下劃線 (私有)
雙下劃線前綴用于實現名稱改寫(name mangling),使得屬性或方法在類外部無法輕易訪問。Python會將這些名稱改寫為
_ClassName__variableName
的形式,從而實現基本的私有化。
示例:
get 私有屬性
class Hello:__private_var = "我是私有的屬性"def __private_method(self):return "我是私有的方法"# 用于訪問私有屬性def get_private_var(self):return self.__private_var# 用于訪問私有方法def get_private_method(self):return self.__private_method()hello = Hello()
# 以下訪問會報錯
# print(hello.__private_var) # 出異常 AttributeError
# print(hello.__private_method()) # 出異常 AttributeError# 方式一:
# 通過類內部方法間接訪問
print(hello.get_private_var()) # 輸出:我是私有的屬性
print(hello.get_private_method()) # 輸出:我是私有的方法# 方式二:
# 通過名稱改寫訪問,改寫規則是 `_類名__變量方法名`
print(hello._Hello__private_var) # 輸出:我是私有的屬性
print(hello._Hello__private_method()) # 輸出:我是私有的方法
set 私有屬性
class Hello:__private_var = "20"# 獲取私有屬性值def get_private_var(self):return self.__private_var# 修改私有屬性值def set_private_var(self, __private_var):self.__private_var = __private_varhello = Hello()# 獲取修改前的數據
print(hello.get_private_var()) # 20# 修改數據
hello.set_private_var("10")# 獲取修改后的數據
print(hello.get_private_var()) # 10
私有權限對于繼承的影響
私有屬性和方法:在子類中無法直接訪問父類的私有屬性和方法。這是因為它們被名稱改寫,只有通過父類提供的公有方法間接訪問。例如,通過
get_private_var()
可以訪問父類的私有成員。受保護屬性和方法:子類可以直接訪問和調用父類的受保護屬性和方法,因為單下劃線只是一個約定,而不是嚴格的訪問控制。
公有屬性和方法:子類可以直接訪問和調用父類的公有屬性和方法。