Python 簡易手冊
單元 62 - 繼承
Python 是物件導向程式語言 (object-oriented programming language) ,物件導向程式設計 (object-oriented programming) 有三大特性,分別是封裝 (encapsulation) 、繼承 (inheritance) 與多型 (polymorphism) 。所謂繼承其實只是讓類別能從其他類別擴充,也就是把共通功能放在父類別 (superclass) ,由子類別 (subclass) 繼承父類別,讓子類別具有共通功能,同時子類別可以額外定義專屬功能。
中文繼承隱含長輩死去,晚輩繼承遺產的意思,但是在物件導向程式中並沒有這個意思,事實上程式執行時,父類別跟子類別是同時存在的,但是早期把 inherit 翻譯成「繼承」,這裡是繼續沿用「繼承」及相關的翻譯方式。
以下示範繼承的寫法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # 定義父類別 class Demo: pass # 定義子類別 class Demo2(Demo): pass # 印出類別 print(Demo) print(Demo2) # 檔名: class_demo22.py # 說明: 《Python簡易手冊》的範例 # 網址: http://kaiching.org # 作者: Kaiching Chang # 時間: 2024 年 3 月 |
單元 54 - 類別介紹類別 (class) 的基本概念,單元 61 - 封裝介紹物件導向程式設計的第一項特性 - 封裝,單元 64 - 多型會介紹物件導向程式設計的第三項特性 - 多型,單元 49 - pass 陳述與省略符號 ...介紹關鍵字 (keyword) pass 的用法。
繼承是在子類別識別字 (identifier) 後面加上小括弧,小括弧中是父類別的識別字
5 6 7 | # 定義子類別 class Demo2(Demo): pass |
底下是印出類別名稱,執行結果如下
> python class_demo22.py |
<class '__main__.Demo'> <class '__main__.Demo2'> |
> |
內建函數 (built-in function) isinstance() 可以判斷參數 (parameter) 是否為某類別的實體物件,另一個內建函數 issubclass() 則可以判斷第一個參數是否為第二個參數的子類別,例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 定義父類別 class Demo: pass # 定義子類別 class Demo2(Demo): pass # 建立物件 a = Demo() b = Demo2() # 判斷 a 是否為 Demo 的實體 print(isinstance(a, Demo)) # 判斷 Demo2 是否是 Demo 的子類別 print(issubclass(Demo2, Demo)) # 檔名: class_demo23.py # 說明: 《Python簡易手冊》的範例 # 網址: http://kaiching.org # 作者: Kaiching Chang # 時間: 2024 年 3 月 |
此例判斷變數 a 是否為 Demo 類別的實體,另外判斷 Demo2 類別是否為 Demo 類別的子類別,執行結果如下
> python class_demo23.py |
True True |
> |
子類別物件預設可以直接使用父類別的屬性 (attribute) 跟方法 (method) ,但是如果子類別定義跟副類別相同名稱的方法,就會以子類別定義的為主,這叫做改寫 (override) ,例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # 定義父類別 class Demo: # 父類別的方法 def do_something(self): print("aaa") # 定義子類別 class Demo2(Demo): pass # 定義子類別 class Demo3(Demo): # 改寫父類別的方法 def do_something(self): print("bbb") # 建立物件 a = Demo() b = Demo2() c = Demo3() # 呼叫方法 a.do_something() b.do_something() c.do_something() # 檔名: class_demo24.py # 說明: 《Python簡易手冊》的範例 # 網址: http://kaiching.org # 作者: Kaiching Chang # 時間: 2024 年 3 月 |
單元 55 - 實體屬性與方法介紹如何定義實體屬性及實體方法。
這個例子定義了三個類別,其中 Demo 是 Demo2 與 Demo3 的父類別, Demo3 改寫 Demo 的 do_something() 方法,執行結果如下
> python class_demo24.py |
aaa aaa bbb |
> |
如果子類別改寫父類別的方法後,仍希望使用父類別方法的定義,那就要用內建函數 super() 呼叫父類別方法,舉例如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | # 定義父類別 class Demo: # 定義父類別的建構子 def __init__(self, p): self.a = p self.__b = 13 # 定義父類別的字串表達方式 def __str__(self): return "Demo" # 定義父類別的方法 def do_something(self): return self.__b # 定義子類別 class Demo2(Demo): # 定義子類別的建構子 def __init__(self, p1, p2): # 呼叫父類別的建構子 super().__init__(p1) # 設定子類別的屬性 self.b = p2 # 定義子類別的字串表達方式 def __str__(self): # 加上父類別的字串表達方式 return super().__str__() + "2" # 改寫父類別的方法 def do_something(self): # 呼叫父類別的方法 return super().do_something() # 執行部分 d = Demo2(11, 12) print(d) print(d.a) print(d.b) print(d.do_something()) # 檔名: class_demo25.py # 說明: 《Python簡易手冊》的範例 # 網址: http://kaiching.org # 作者: Kaiching Chang # 時間: 2024 年 3 月 |
單元 56 - 建構子與解構子介紹如何定義建構子。
這個例子中,由於父類別有屬性需要透過參數設定,因此由 super() 呼叫父類別的 __init__() 來設定
18 19 20 21 22 23 | # 定義子類別的建構子 def __init__(self, p1, p2): # 呼叫父類別的建構子 super().__init__(p1) # 設定子類別的屬性 self.b = p2 |
字串 (string) 方法是用父類別的字串方法加上子類別的指定字串
25 26 27 28 | # 定義子類別的字串表達方式 def __str__(self): # 加上父類別的字串表達方式 return super().__str__() + "2" |
do_something() 則是直接回傳父類別的 do_somthing() ,由於父類別的 do_somthing() 回傳封裝屬性 __b ,因此這裡也是取得這個屬性值
30 31 32 33 | # 改寫父類別的方法 def do_something(self): # 呼叫父類別的方法 return super().do_something() |
注意,子類別不能直接使用父類別封裝過的屬性或方法,但是可以透過父類別公開的方法來存取,此例執行結果如下
> python class_demo25.py |
Demo2 11 12 13 |
> |