繼承機制經常用于創建和現有類功能類似的新類,又或是新類只需要在現有類基礎上添加一些成員(屬性和方法),但又不想直接將現有類代碼復制給新類,
也就是說,通過使用繼承這種機制,可以輕松實作類的重復使用,相同的代碼不需要重復的撰寫,提高開發的效率,
一、單繼承
繼承的概念:子類擁有父類的所有方法和屬性,

不使用繼承分析:
Animal 中有4個方法,Dog 類中有5個方法,Dog 類中的4個方法可以直接從 Animal 中復制粘貼過來,Dog 類其實只需要單獨開發 bark 方法,
XiaoTianQuan 類具有普通 Dog 的行為,6個方法中的前5個方法和 Dog 類的是重復的,可以直接復制過來,只需要單獨開發 fly 方法,
假設我們在開發的程序中,Animal 中 喝水的方法需要修改,那就意味著 Dog 和 XiaoTianQuan 中的喝水方法也要跟著修改,這樣就顯得太麻煩了,
接下來,我們來使用繼承的方式,
1、繼承的語法
class 類名(父類名):
...
...
子類繼承自父類,可以直接享受父類中已經封裝好的方法,不需要再次開發,
子類中應該根據職責,封裝子類特有的屬性和方法,
實體:
class Animal:
def eat(self):
print("吃")
def drink(self):
print("喝")
def run(self):
print("跑")
def sleep(self):
print("睡")
class Dog(Animal):
# 子類擁有父類的所有屬性和方法
def bark(self):
print("汪汪叫")
# 創建一個物件 - 狗物件
wangcai = Dog()
wangcai.eat() # 吃
wangcai.drink() # 喝
wangcai.run() # 跑
wangcai.sleep() # 睡
wangcai.bark() # 汪汪叫
在對于繼承的概念上可能存在不一樣的描述,不過都是指同一件事情,比如:
Dog 類是 Animal 類的子類,Animal 類是 Dog 類的父類,Dog 類從 Animal 類繼承,
Dog 類是 Animal 類的派生類,Animal 類是 Dog 類的基類,Dog 類從 Animal 類派生,
繼承的傳遞性
C 類從 B 類繼承,B 類又從 A 類繼承,那么 C 類就具有 B 類和 A 類的所有屬性和方法,
2、繼承中方法的重寫
當父類的方法實作不能滿足子類需求時,可以對方法進行重寫(override),

重寫父類方法有兩種情況:
1) 覆寫父類的方法
如果在開發中,父類的方法實作和子類的方法實作完全不同,就可以使用覆寫的方式,在子類中重新撰寫父類的方法實作,
具體的實作方式,就相當于在子類中定義了一個和父類同名的方法并且實作,
重寫之后,在運行時,只會呼叫子類中重寫的方法,而不再會呼叫父類封裝的方法,
class Dog():
def bark(self):
print("汪汪叫")
class XiaoTianQuan(Dog):
def fly(self):
print("我會飛")
def bark(self):
print("叫得跟神一樣...")
xtq = XiaoTianQuan()
# 如果子類中,重寫了父類的方法
# 在使用子類物件呼叫方法時,會呼叫子類中重寫的方法
xtq.bark() # 叫得跟神一樣...
2) 對父類方法進行擴展
如果在開發中,子類的方法實作中包含父類的方法實作,父類原本封裝的方法實作是子類方法的一部分,那么就可以使用擴展的方式,
在子類中重寫父類的方法,在需要的位置使用 super().父類方法來呼叫父類方法的執行,在代碼其他的位置針對子類的需求,撰寫子類特有的代碼實作,
class Dog():
def bark(self):
print("汪汪叫")
class XiaoTianQuan(Dog):
def fly(self):
print("我會飛")
def bark(self):
# 1. 針對子類特有的需求,撰寫代碼
print("神一樣的叫喚...")
# 2. 使用 super(). 呼叫原本在父類中封裝的方法
super().bark()
xtq = XiaoTianQuan()
xtq.bark()
# 神一樣的叫喚...
# 汪汪叫
關于 super
在 Python 中 super 是一個特殊的類,super() 就是使用 super 類創建出來的物件,最常使用的場景就是在重寫父類方法時,呼叫在父類中封裝的方法實作,
3、父類的私有屬性和私有方法
子類物件不能在自己的方法內部,直接訪問父類的私有屬性或私有方法,
私有屬性、方法通常用于做一些內部的事情,它們是物件的隱私,不對外公開,外界以及子類都不能直接訪問,不過子類物件可以通過父類的公有方法間接訪問到私有屬性或私有方法,
示例:

根據上面的類圖,得出以下結論:B 的物件不能直接訪問 __num2 屬性,B 的物件不能在 demo 方法內訪問 __num2 屬性,B 的物件可以在 demo 方法內,呼叫父類的 test 方法,父類的 test 方法內部,能夠訪問 __num2 屬性和 __test 方法,
二、多繼承
子類可以擁有多個父類,并且具有所有父類的屬性和方法,
事實上,大部分面向物件的編程語言,都只支持單繼承,即子類有且只能有一個父類,而 Python 卻支持多繼承,
例如:孩子會繼承自己父親和母親的特性,

語法:
class 子類名(父類名1, 父類名2...)
pass
示例:
class A:
def test(self):
print("test 方法")
class B:
def demo(self):
print("demo 方法")
class C(A, B):
"""多繼承可以讓子類物件,同時具有多個父類的屬性和方法"""
pass
c = C()
c.test() # test 方法
c.demo() # demo 方法
多繼承的使用注意事項
如果父類之間存在同名的屬性或者方法,應該盡量避免使用多繼承,以免產生混淆的情況,
但是,如果確實繼承了存在同名屬性和方法的父類,那么,子類物件在呼叫方法時,會呼叫哪一個父類中的方法呢?
class A:
def test(self):
print("A --- test 方法")
def demo(self):
print("A --- demo 方法")
class B:
def test(self):
print("B --- test 方法")
def demo(self):
print("B --- demo 方法")
class C(B, A):
pass
# 創建子類物件
c = C()
c.test() # B --- test 方法
c.demo() # B --- demo 方法
從效果上來看,子類呼叫父類的方法的順序好像根據繼承父類的順序來的,但其實不能這么簡單的判定,
Python 中的 MRO —— 方法搜索順序
Python 中針對類提供了一個內置屬性 mro 可以查看方法搜索順序,
MRO 是 method resolution order,主要用于在多繼承時判斷方法、屬性的呼叫路徑,
緊接上面的例子:
# 確定C類物件呼叫方法的順序
print(C.__mro__)
# (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
在搜索方法時,是按照 __mro__ 的輸出結果從左至右的順序查找的;如果在當前類中找到方法,就直接執行,不再搜索;如果沒有找到,就查找下一個類中是否有對應的方法,如果找到,就直接執行,不再搜索;如果找到最后一個類,還沒有找到方法,程式報錯,
雖然 Python 在語法上支持多繼承,但逼不得已,建議大家不要使用多繼承,
和單繼承相比,多繼承容易讓代碼邏輯復雜、思路混亂,一直備受爭議,中小型專案中較少使用,后來的 Java、C#、PHP 等干脆取消了多繼承,
如果一個類的父類不是 object,在重寫初始化方法時,一定要先 super() 一下父類的 __init__ 方法,保證父類中實作的 __init__ 代碼能夠被正常執行,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/20976.html
標籤:Python
下一篇:python基礎一
