6. 類別的繼承
• 學習目標
– 瞭解繼承目的
– 認識鴨子定型
– 重新定義方法
– 認識 object
– 建立、尋找文件資源
繼承共同行為
• 重複在程式設計上,就是不好的訊號
鴨子定型
• 動態定型語言界流行的鴨子定型
– 如果它走路像個鴨子,游泳像個鴨子,叫聲像
個鴨子,那它就是鴨子。
• 思考物件的行為,而不是物件的種類
• 具有比較高的通用性
重新定義方法
• 在多數的情況下,檢查型態而給予不同的
流程行為,對於程式的維護性有著不良的
影響,應該避免:
• 在繼承後若打算基於父類別的方法實作來
重新定義某個方法,可以使用 super() 來
呼叫父類別方法:
定義抽象方法
• 如果希望子類別在繼承之後,一定要實作
的方法
– 在父類別中指定 metaclass 為 abc 模組的
ABCMeta 類別
– 在指定的方法上標註 abc 模組的
@abstractmethod 來達到需求
• 如上定義就不能使用 Role 來建構物件了,否
則會發生 TypeError
• 若類別繼承了 Role 類別,沒有實作fight()
方法,在實例化時也會發生 TypeError:
初識 object 與 super()
• 若沒有指定父類別,那麼就是繼承 object
類別
• 若沒有定義的方法,某些場合下必須呼叫
時,就會看看父類別中是否有定義
• 如果定義了自己的方法,那麼就會以你定
義的為主,不會主動呼叫父類別的方法
Rich comparison 方法
• object 類別定義了__lt__()、
__le__()、__eq__()、__ne__()、
__gt__()、__ge__()
• 定義了物件之間使用<、<=、==、!=、>、
>=等比較時,應該要有的比較結果
• 想要能使用==來比較兩個物件是否相等,
必須定義 __eq__() 方法
• __ne__() 預設會呼叫 __eq__() 並反
相其結果
• object 定義的 __eq__() 方法,預設
是使用 is 來比較兩個物件
• 實作 __eq__() 時通常也會實作
__hash__()
• __lt__() 與 __gt__() 互補,而
__le__() 與 __ge__() 互補
• 基本上只要定義 __gt__()、__ge__()
就可以
• 真的需要定義這整組方法的行為,可以使
用 functools.total_ordering
使用 enum 列舉
• 透過 dict 列舉:
• 透過類別列舉:
• 從 Python 3.4 開始新增了 enum 模組
• 列舉物件上具有 name 與 value,可用來
取得列舉名稱與列舉值
• 也可以使用 [] 指定列舉名稱取得列舉物件。
• 可以使用 for in 來迭代列舉:
• 繼承 Enum 或 IntEnum 類別定義列舉時,列
舉名稱不得重複,然而,列舉值可以重複。
• 如果想要在列舉時值不得重複,可以在類
別上加註 enum 模組的 @unique
多重繼承
• 可以進行多重繼承,也就是一次繼承兩個
父類別的程式碼定義
• 父類別之間使用逗號作為區隔
• 如果繼承時多個父類別中有相同的方法名
稱,就要注意搜尋的順序
• 基本上是從子類別開始尋找名稱,接著是
同階層父類別由左至右搜尋,再至更上層
• 同一階層父類別由左至右搜尋,直到達到
頂層為止
• 一個子類別在尋找指定的屬性或方法名稱
時,會依據類別的 __mro__ 屬性的
tuple 中元素順序尋找
• MRO 全名是 Method Resolution Order,
• 如果想要知道直接父類別的話,則可以透
過類別的__bases__來得知
• __mro__ 是唯讀屬性
• 改變 __bases__ 來改變直接父類別,從而
使得 __mro__ 的內容也跟著變動
• 如果定義類別時,python 直譯器無法生成
__mro__,會引發 TypeError
• 子類別繼承兩個父類別的順序,會決定抽
象方法是否得到實作
• 判定一個抽象方法是否有實作,也是依照
__mro__中類別的順序
建立 ABC
• 多重繼承的能力,通常建議只用來繼承
ABC,也就是抽象基礎類別
• 一個抽象基礎類別,不會定義屬性,也不
會有 __init__() 定義
• 來考慮一個 Ball 類別
探討 super()
• 無引數 super()呼叫,是
super(__class__, <first
argument>) 的簡便方法
• 在一個綁定方法中,就相當於使用
super(__class__, self)
• 在 @classmethod 標註的方法中,就相
當於呼叫super(__class__, clz)。
• 呼叫 super(type, obj) 時,會使用
obj 的類別之 __mro__ 清單
• 從指定的 type 之下個類別開始查找,看
看是否有指定的方法
– 若有的話,將 obj 當作是呼叫方法的首引數
• 呼叫 super(type, type2) 時,會使
用 type2 的 __mro__ 清單
• 從指定的 type 之下個類別開始查找,看
看是否有指定的方法,若有的話,將
type2 當作是呼叫方法的第一個引數
• @staticmethod 標註的方法呢?
DocStrings
• 標準程式庫原始碼本身就附有文件
• 想為自訂函式定義 DocStrings:
• 在函式、類別或模組定義的一開頭,使用
''' 包括起來的多行字串,會成為函式、
類別或模組的 __doc__ 屬性值
• 慣例上,單行的 DocStrings 會是在一行中
使用 ''' 左右含括起來
• 函式或方法中的 DocStrings 若是多行字串,
''' 緊接的第一行,會是函式的簡短描述
• 之後空一行後,才是參數或其他相關說明,
最後換一行並縮排結束
• 如果是類別或模組的多行 DocStrings,會
是在 ''' 後馬上換行,以相同層次縮排
• 如果想針對套件來撰寫 DocStrings
查詢官方文件
類別的繼承
類別的繼承

類別的繼承