iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0
Software Development

跟著 OXXO 一起學 Python系列 第 27

( Day 13.2 ) Python 繼承 inheritance

  • 分享至 

  • xImage
  •  

開始使用 Python 的類別 class 去解決問題時,通常會遇到需要修改類別的狀況,這往往會造成原始類別的複雜化或破壞原本的功能,這時就需要使用類別裡「繼承」的方式來進行處理,這篇教學將會介紹 Python 中的「繼承」。

原文參考:繼承 inheritance

本篇使用的 Python 版本為 3.7.12,所有範例可使用 Google Colab 實作,不用安裝任何軟體 ( 參考:使用 Google Colab )

什麼是繼承 inheritance?

繼承,就如同字面上的意思:父親繼承了爺爺的東西,兒子繼承父親的東西...不斷繼承下去*,繼承表示可以用既有的類別去建立一個新的類別,並加入一些新的東西或修改新的類別,當使用繼承時,新的類別會自動使用舊的類別內所有的程式碼*。

下方的程式碼,名為 son 的類別使用「class son(father)」的語法,繼承了 fatehr 的程式碼,當 oxxo 為 son 時,就能夠呼叫出 fatehr 的所有屬性。

class father():         # fatehr 類別
    def __init__(self):
        self.eye = 2
        self.ear = 2
        self.nose = 1
        self.mouth = 1

class son(father):          # son 類別繼承了 fatehr 類別裡所有的方法
    def language(self):     # son 類別具有 language 的方法
        print('chinese')    # 從 father 繼承了五官,然後自己學會講中文

oxxo = son()                # 設定 oxxo 為 son()
print(oxxo.eye)             # 印出 2
oxxo.language()             # 印出 chinese

繼承時會覆寫方法

在繼承時,如果子類類別裡某個方法的名稱和父類別相同,則會完全複寫父類別的方法,下面的程式碼,son 類別使用了 init 的方法,就覆寫了原本 fatehr 的 init 方法,導致讀取 oxxo.ear 時發生錯誤 ( 因為 son 的方法裡不存在 ear 的屬性 )

class father():
    def __init__(self):
        self.eye = 2
        self.ear = 2
        self.nose = 1
        self.mouth = 1

class son(father):
    def __init__(self):   # 使用了 __init 的方法
        self.eye = 100

oxxo = son()
print(oxxo.eye)    # 100
print(oxxo.ear)    # 發生錯誤  'son' object has no attribute 'ear'

使用 super()

如果不想要覆寫父類別的方法,又想要使用父類別的方法,就可以使用「super()」來實現,下方的程式碼,使用 super() 繼承了 father init 裡所有的屬性,然後再將 eye 的屬性覆寫為 100。

class father():
    def __init__(self):
        self.eye = 2
        self.ear = 2
        self.nose = 1
        self.mouth = 1

class son(father):
    def __init__(self):
        super().__init__()   # 使用 super() 繼承 father __init__ 裡所有屬性
        self.eye = 100       # 如果屬性相同,則覆寫屬性

oxxo = son()
print(oxxo.eye)              # 100
print(oxxo.ear)              # 2

多重繼承

繼承不僅能進行單一繼承,也可以進行多重繼承,例如可以從爸爸身上繼承基因,同時也可以從媽媽身上繼承基因一般,下方的例子,son 從 father 繼承了五官,從 mother 繼承了 language 和 skill。

class father():          # father 類別
    def __init__(self):  # father 的方法
        self.eye = 2
        self.ear = 2
        self.nose = 1
        self.mouth = 1

class mother():          # mother 類別
    def language(self):  # mother 的方法
        print('english')
    def skill(self):
        print('painting')

class son(father, mother):    # 繼承 father 和 mother
    def play(self):           # son 自己的方法
        print('ball')

oxxo = son()
print(oxxo.eye)        # 2
oxxo.skill()           # painting
oxxo.play()            # ball

進行多重繼承時,同樣會有「覆寫方法」的狀況出現,而覆寫方法的順序是從「讀取類別的順序」決定,舉例來說,下方的 c 和 d 兩個類別,雖然都多重繼承了 a 和 b,但因為讀取的順序不同,所以呈現的結果也會不同。

class a():
    def says(self):
        print('a')

class b():
    def says(self):
        print('b')

class c(a, b):    # 先讀取 a 再 b,就會將 a 裡的方法,覆寫 b 裡同名的方法
    pass

class d(b, a):    # 先讀取 b 再 a,就會將 b 裡的方法,覆寫 a 裡同名的方法
    pass

ccc = c()
ddd = d()
ccc.says()    # a
ddd.says()    # b

多層繼承

繼承裡除了多重繼承,也有「多層繼承」的概念,就如同父親繼承了爺爺的東西,兒子繼承父親的東西,多層繼承同樣存在覆寫方法的原則,如果遇到同名的方法就會覆寫,除非使用 super() 的方法處理,下方的例子裡, father 繼承了 grandpa 的五官,son 又繼承了 father 的方法,最後 son 就擁有 father 和 grandpa 所有的方法。

class grandpa():
    def __init__(self):
        self.eye = 2
        self.ear = 2
        self.nose = 1
        self.mouth = 1

class father(grandpa):
    def language(self):
        print('english')
    def skill(self):
        print('painting')

class son(father):
    def play(self):
        print('ball')

oxxo = son()
print(oxxo.eye)    # 2
oxxo.skill()       # painting
oxxo.play()        # ball

私有方法 ( 雙底線 )

在實作一個類別的過程裡,可能會遇到有些方法是該類別內部使用,不想讓繼承該類別的子類別可以用的,這時就需要建立「私有方法」,私有方法可以使用「雙底線 + 名稱」來建立,私有方法建立後,不論是從外部讀取或是子類別的繼承,都無法使用該方法,只有在該類別裡的其他方法才能調用

下方的程式碼 grandpa 有一個 __money 的方法,但是除非知道 getMoney 的方法,不然都無法直接讀取 ( 爺爺有一筆錢,除非你知道方法,不然無法繼承成功 )。

class grandpa():
    def __init__(self):
        self.mouth = 1
    def __money(self):     # 建立一個私有方法 __money
        print('$1000')
    def getMoney(self):    # 建立一個 getMoney 的方法,執行私有方法 __money
        self.__money()

class father(grandpa):
    def skill(self):
        print('painting')

class son(father):
    def play(self):
        print('ball')

oxxo = son()
oxxo.getMoney()         # $1000
oxxo.__money()          # 發生錯誤  'son' object has no attribute '_money'

更多教學

大家好,我是 OXXO,是個即將邁入中年的斜槓青年,我有個超過一千篇教學的 STEAM 教育學習網,有興趣可以參考下方連結呦~ ^_^


上一篇
( Day 13.1 ) Python 類別 class
下一篇
( Day 14.1 ) Python 內建函式 ( 檔案讀寫 open )
系列文
跟著 OXXO 一起學 Python101
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言