子類別也可依需要改寫 (override) 父類別的方法,這是說子類別需要用到與父類別具有相同名稱的方法,但是子類別需要的功能有所修改、擴充或增加,因此當子類別裡頭定義與父類別相同名稱的方法時,就會改寫父類別的方法。經過改寫,子類別的方法完全屬於子類別所有,例如以下程式
class Demo: __x = 0 def __init__(self, i): self.__i = i Demo.__x += 1 def __str__(self): return str(self.__i) def hello(self): print("hello " + self.__str__()) @classmethod def getX(cls): return cls.__x class SubDemo(Demo): def __init__(self, i, j): self.__i = i self.__j = j def __str__(self): return str(self.__i) + "+" + str(self.__j) a = SubDemo(1234) a.hello() print("a.__x =", a.getX()) b = SubDemo(56, 78) b.hello() print("b.__x =", b.getX()) print() print("a.__x =", a.getX()) print("b.__x =", b.getX()) # 《程式語言教學誌》的範例程式 # http://pydoing.blogspot.com/ # 檔名:cla19.py # 功能:示範 Python 程式 # 作者:張凱慶 # 時間:西元 2010 年 12 月
執行結果如下
Demo 為父類別,定義四個方法, SubDemo 為子類別,改寫 Demo 的兩個方法,包括 __init__() 與 __str__() 。
我們可以發現, Demo 有個 __x 變數,原本用來算有多少 Demo 實體 (instance) 被建立,我們想這應該要包括子類別 SubDemo 的實體數量,也就是說, __x 應該等於 Demo 實體總數加上 SubDemo 實體總數。此例中我們建立兩個 SubDemo 實體,可是 __x 卻等於 0 。
這是為什麼呢?因為此例中 Demo 的 __init__() 方法從頭到尾沒有被呼叫過,因此 __x 始終保持為初值 0 。解決這個問題的方法很簡單,一個幾單的途徑是在子類別 SubDemo 新增一個 __x ,但是這樣一來就只能累計 SubDemo 的實體數量,若是還有其他子類別繼承自 Demo ,這就無法一同列入計算了。
另一個解決途徑是在子類別改寫的方法中先呼叫 (call) 父類別的方法,這可利用內建函數 (function) super() ,如下
class Demo: __x = 0 def __init__(self, i): self.__i = i Demo.__x += 1 def __str__(self): return str(self.__i) def hello(self): print("hello " + self.__str__()) @classmethod def getX(cls): return cls.__x class SubDemo(Demo): def __init__(self, i, j): super().__init__(i) self.__j = j def __str__(self): return super().__str__() + "+" + str(self.__j) a = SubDemo(12, 34) a.hello() print("a.__x =", a.getX()) b = SubDemo(56, 78) b.hello() print("b.__x =", b.getX()) print() print("a.__x =", a.getX()) print("b.__x =", b.getX()) # 《程式語言教學誌》的範例程式 # http://pydoing.blogspot.com/ # 檔名:cla20.py # 功能:示範 Python 程式 # 作者:張凱慶 # 時間:西元 2010 年 12 月
執行結果如下
第 19 行到第 21 行
def __init__(self, i, j): super().__init__(i) self.__j = j
SubDemo 的 __init__() 定義中,我們利用 super() 呼叫父類別 Demo 的 __init__() ,因此需提供 i 當作參數 (parameter) 。注意,這裡 self.__i 變成父類別的私有屬性。
第 23 行到第 24 行
def __str__(self): return super().__str__() + "+" + str(self.__j)
這裡的 __str__() ,在 return 後的運算式 (expression) 先呼叫 super().__str__() ,因為 self.__i 已經變成父類別 Demo 私有屬性,因此需要先呼叫父類別的 __str__() 。
中英文術語對照 | |
---|---|
子類別 | subclass |
屬性 | attribute |
方法 | method |
父類別 | superclass |
繼承 | inherit |
改寫 | override |
實體 | instance |
呼叫 | call |
函數 | function |
參數 | parameter |
運算式 | expression |
參考資料
http://docs.python.org/py3k/tutorial/classes.html
http://docs.python.org/py3k/reference/compound_stmts.html
http://docs.python.org/py3k/tutorial/classes.html
http://docs.python.org/py3k/reference/compound_stmts.html
1 則留言:
在第一個範例裡
a = SubDemo(1234)應該會報錯
因為找不到只吃一個引數的SubDemo建構子
張貼留言