添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

類別 class

當學習 Python 到某種程度後,就會開始進入物件導向的領域,而「類別」就是學習物件導向的基礎,這篇教學將會介紹 Python 裡的類別 class,並進一步說明類別和物件的關係。

快速導覽: 什麼是類別? 什麼是物件? 建立類別 多個物件同一個類別 覆寫屬性 @property 唯讀屬性

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

什麼是類別 class?

類別,可以比喻成一張「藍圖」, 不同的藍圖會有不同的「屬性」,根據不同的屬性,就會建構出不同的物體 。或者也可將類別想像成一個「人」, 不同的人會有不同的「特徵」( 屬性 ),根據不同的特徵,就會產生不同樣的人

舉例來說,下方的程式碼建立了一個名為 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 屬性 )。

什麼是物件 object?

在 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 唯讀屬性

    如果在類別裡有些屬性不希望被外部更動,就能夠使用 @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
              

    如果有任何建議或問題,可傳送「意見表單」給我,謝謝~