當學習 Python 到某種程度後,就會開始進入物件導向的領域,而「類別」就是學習物件導向的基礎,這篇教學將會介紹 Python 裡的類別 class,並進一步說明類別和物件的關係。
原文參考:類別 class
本篇使用的 Python 版本為 3.7.12,所有範例可使用 Google Colab 實作,不用安裝任何軟體 ( 參考:使用 Google Colab )
類別,可以比喻成一張「藍圖」,不同的藍圖會有不同的「屬性」,根據不同的屬性,就會建構出不同的物體。或者也可將類別想像成一個「人」,不同的人會有不同的「特徵」( 屬性 ),根據不同的特徵,就會產生不同樣的人。
舉例來說,下方的程式碼建立了一個名為 human ( 人 ) 的類別,類別預設有四個屬性,分別是兩個眼睛 eye、兩個耳朵 ear、一個鼻子 nose 和一張嘴巴 mouth,接著透過這個類別誕生了一個特定的人 oxxo,這個人就會具有對應的屬性 ( 後面會介紹如何建立類別 )。
class human():
def __init__(self): # 建立預設屬性的寫法
self.eye = 2 # 兩個眼睛
self.ear = 2 # 兩個耳朵
self.nose = 1 # 一個鼻子
self.mouth = 1 # 一張嘴巴
oxxo = human() # 製作一個名為 oxxo 的物件
print(oxxo.eye) # 得到 2 ( 印出 oxxo 的 eye 屬性 )。
在 Python 裡的任何東西 ( 數字、文字、函式...等 ) 都是物件,只是 Python 預設會將大部份物件的機制隱藏,只顯示最常使用的方法,除非有特殊需求,不然不需要更動到預設物件的行為。
什麼是物件呢?物件是一種自訂的資料結構,裡面可能包含了各種變數、屬性、函式或方法,一個物件可以透過他的屬性或方法,定義他和別的物件進行互動。
建立類別的方式類似建立一個函式,差別在於函式使用 def 開頭,而類別使用 class 開頭,下方的程式碼會建立一個「空」的類別 human ( 很像一個人在最開始只是一個細胞,身上什麼器官都還沒長出來 ):
class human():
pass # 使用 pass 可以建立一個空類別
接著使用建立類別的預設方法「__init__
」( 注意前後是兩條底線 ),將預設的屬性加入類別裡。
def __init__(self)
預設帶有一個 self 參數,代表透過類別建立的物件本體,內容使用「.屬性」就能將指定的屬性加入類別中。__init__
可以不用定義,但如果需要有一些預設的屬性,就可以定義在裡面
class human():
def __init__(self): # 建立預設屬性的寫法
self.eye = 2 # 兩個眼睛
self.ear = 2 # 兩個耳朵
self.nose = 1 # 一個鼻子
self.mouth = 1 # 一張嘴巴
除了預設的屬性,也可以自訂屬性,下方的例子定義了 say 和 play 兩個函式作為 human 的屬性,執行後,就等同於一個名為 oxxo 的人說話和玩棒球。
注意,字定義屬性的第一個參數也都必須是 self。
class human():
def __init__(self):
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
def say(self, msg): # 定義 say
print(msg)
def play(self, thing): # 定義 play
print(thing)
oxxo = human()
oxxo.say('hello') # hello
oxxo.play('baseball') # baseball
屬性除了可以定義在類別裡,也可以從外部定義,下面的程式碼額外定義了手 hand 和腳 leg 兩個屬性。
class human():
def __init__(self):
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
def say(self, msg):
print(msg)
def play(self, thing):
print(thing)
human.hand = 2 # 定義 hand 屬性
human.leg = 2 # 定義 leg 屬性
oxxo = human()
print(oxxo.hand) # 2
print(oxxo.leg) # 2
剛剛有提到 self 這個參數,這個參數代表「透過類別建立的物件本體」,使用 self 可以讀取到這個物件的所有屬性,下方的例子從外部定義了 oxxo.name 的屬性,在 human 裡就能使用 self.name 取得這個屬性。
class human():
def __init__(self):
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
def say(self, msg):
print(f'{self.name} say: {msg}') # 使用 self.name 取得 name 屬性的值
def play(self, thing):
print(thing)
oxxo = human()
oxxo.name = 'oxxo' # 設定 name 屬性
oxxo.say('hello') # oxxo say: hello
一個類別可以產生多個物件 ( 人 human 的類別可以產生無數不同的人 ),每個物件產生後,也可以定義自己特殊的屬性,就如同人誕生後,雖然都有眼睛鼻子嘴巴,但某些人會去學畫畫,某些人會去學鋼琴,下方的程式碼會產生oxxo 和 gkpen 兩個不同的人,oxxo 會自定義 age 屬性,gkpen 會自定義 weight 屬性。
class human():
def __init__(self):
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
def say(self, msg):
print(f'{self.name} say: {msg}')
def play(self, thing):
print(thing)
oxxo = human() # 定義 oxxo
gkpen = human() # 定義 gkpen
oxxo.name = 'oxxo' # oxxo 的名字叫做 oxxo
oxxo.age = 18 # oxxo 的 age 為 18
gkpen.name = 'gkpen' # gkpen 的名字叫做 gkpen
gkpen.weight = 70 # gkpen 的 weight 為 70
oxxo.say('hello') # oxxo say: hello
print(oxxo.age) # 18
gkpen.say('song') # gkpen say: song
print(gkpen.weight) # 70
如果覺得這樣子定義比較麻煩,也可以在建立類別時,預先設定好一些參數,接著透過類別建立物件時,在做動態的調整,例如下方的例子,在 init 裡建立 age、weight 的參數,建立物件時就能動態傳入。
class human():
def __init__(self, age, weight): # 新增 age 和 weight 參數
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
self.age = age # 讀取參數,變成屬性
self.weight = weight # 讀取參數,變成屬性
def say(self, msg):
print(f'{self.name} say: {msg}')
def play(self, thing):
print(thing)
oxxo = human(18, 68) # 建立物件時,設定參數數值
gkpen = human(15, 70) # 建立物件時,設定參數數值
print(oxxo.age, oxxo.weight) # 18, 68
print(gkpen.age, gkpen.weight) # 15, 70
如果從外部定義了和類別屬性名稱相同的屬性,就會覆寫內部屬性,下方的例子,從外部定義了 oxxo.play 的屬性,就覆寫原本的 play 屬性。
class human():
def __init__(self):
self.eye = 2
self.ear = 2
self.nose = 1
self.mouth = 1
def say(self, msg):
print(f'{self.name} say: {msg}')
def play(self, thing):
print(thing)
oxxo = human()
oxxo.play = '???' # 覆寫 play 屬性
print(oxxo.play) # ???
如果在類別裡有些屬性不希望被外部更動,就能夠使用 @property 的裝飾器,將該屬性設為唯讀屬性,下方的例子,oxxo.a 可以將原本的 a 屬性換成 12345,但 oxxo.b 就無法更動 b 屬性,因為 b 屬性已經變成唯讀屬性。
class a:
def a(self):
return 'aaaaa'
@property
def b(self):
return 'bbbbb'
oxxo = a()
oxxo.a = '12345'
print(oxxo.a) # 12345
oxxo.b = '12345'
print(oxxo.b) # 發生錯誤 can't set attribute
大家好,我是 OXXO,是個即將邁入中年的斜槓青年,我有個超過一千篇教學的 STEAM 教育學習網,有興趣可以參考下方連結呦~ ^_^