Python Enum 枚舉教學:有條理管理常數集合的好工具

by 好豪
Published: Updated:

enum 讓程式碼更清晰、好讀,尤其是你管理的常數名稱有意義的情況

Microsoft Enumeration Guide

Python 中的 enum 套件來自 Enumerate 的縮寫,中文可以翻譯為枚舉,功能是讓多個常數值綁定在特定符號組合(例如 1、2、3)。如果你在程式中的某個變數,其被指定的值是來自特定且有限的幾種數值,這時候就很適合使用 enum 來幫助你把程式變漂亮。

我開始學習使用 Python enum 的契機是 2021 年剛加入這間 科技公司 工作時,某次與軟體工程師會議中,在討論 App 產品中的 字重(font weight)資料埋點該如何設計,以了解使用者對特定字體粗細設定的偏好。其中一位工程師提出一個直覺的作法:在 Log 中以整數(Integer)紀錄使用者正在用的字重,雖然我當時覺得可行、立刻同意,然而,另一位較資深的工程師則提出:由於字重只有特定幾種常數值,包括 300、400、500 等等(而不會有 “471” 這種字重數值),所以,這個情境要用 enum 來表述資料會更適當!

字重(font weight)的使用慣例是特定幾種整數常數
例如 300、400、500 等等
正是適合使用 enum 的其中一種情境
(圖片來源:Wikipedia

這則筆記整理了我在上面這項經歷後持續鑽研的 Python enum 用法,我將與你分享用 enum 究竟有什麼好處,文章內也將教學 Python enum 的基本與進階使用技巧。

enum 的使用不只對 Python 設計 App 產品有幫助,資料科學家們也可以透過 enumpandas 分析巨量資料時更有效率!本篇筆記也會分享在 pandas 內使用 enum 的組合技巧,提供一個讓計算速度提升 5 倍的範例,如果你是資料科學愛好者,想必你會有興趣讀下去!


閱讀提醒:

  1. 本文討論的是 enum 套件,而不是 enumerate() 函式,這兩者只是名字長得像、但功能大不相同喔!
  2. Enumenum 是不一樣的。enum 指的是套件(package),Enum 是套件中一個類別(Class),只是 Enum 類別十分常用,所以本文內文可能會有混用的情形,請稍微注意


為什麼需要枚舉與 Enum

使用 enum 來枚舉實際上做的事情,可以簡單理解為:管理一群「成員名稱與成員數值」的對應關係。當你要管理的常數有特定對象、而且數量有限時,特別實用,例如:

  • 月份資料(只有十二個月):成員 November 對應到數值 11
  • 顏色資料(常用的是 RGB 三種原色):成員 Green 對應到數值 2
  • 衣服尺碼資料(從 S 到 XL):成員 Small 對應到數值 1
  • 本文前言提過的字重資料(100、200、300 等):成員 400 對應到 4

比起直接開始宣揚 enum 的好處,我們先從一個簡單的例子來看看沒有使用 enum 會有什麼壞處:

employee = "data scientist"

if employee == "Engineer":
    print("此員工是一位:" + "工程師")
elif employee == "Product Manager":
    print("此員工是一位:" + "產品經理")
elif employee == "Data Scientist":
    print("此員工是一位:" + "資料科學家")
else:
    print("未知的職位")

想想看,你覺得這支超簡單的程式會在畫面上輸出什麼結果呢?跑跑看便知道,答案是 未知的職位

我明明將變數設定成 data scientist 了,在我的 if-else 條件式裡面明明也有包含這個職位,為什麼還是輸出 未知的職位?問題很基本:單純是大小寫不同。

>>> "Data Scientist" == "data scientist"
False

「資料科學家」在程式內用英文表述可能是 Data Scientistdata scientist、也可能是 Data scientist,只有人類看起來意思一樣,程式看起來可是完全不同數值。不同的工程師來寫這支程式,依照個人習慣會有不同表述方法,更慘的是,像上面這種寫法,很容易有錯字(Typo)!

>>> "Data Scientist" == "Data Sciantist" # 眼力大考驗 (˚∀˚)
False

上面的情境正是 enum 能解決的痛點,在 Python 使用 enum 的主要好處是:

  • 增加程式的可讀性(Readability)、讓程式更好維護
  • enum 排除了手動輸入常數打錯字的可能性
  • 變數可能呈現的常數選項變得更一目瞭然、更好管理
    • 例如:避免共同設計此程式的其他工程師寫出不符合規定的常數

在概念上,enum 會把以上範例改寫成:

  • 用數字 1 代表「工程師」
  • 用數字 2 代表「產品經理」
  • 用數字 3 代表「資料科學家」

使用後 enum 後,這支處理職位資訊的程式範例會得到的好處是:

  • 職位名稱與職位數字對應關係是固定的,對應關係以外的都不能用,因此不用怕輸入常數的打字錯誤
    • 不再煩惱該寫 Data Scientist 還是 data scientist,因為最後只會有其中一種被允許使用
  • 不被 enum 管理的職位,就不能(隨意)使用,除非程式設計者加入新職位
    • 範例中只有 3 個職位,如果你想在職位中使用數字 4 代表「業務員」的話,enum 會告訴你違規了!

以上都是概念性地介紹 enum,接下來的筆記會正式開始介紹 Python 中 enum 的操作語法,你將會在語法中更清楚看到使用 enum 的優點。


在此,筆者好豪簡短補充,枚舉(Enumerated Type)是一種程式中表述資料的方法,而不是 Python 獨有的技巧,各個程式語言都有各自的枚舉語法,而 Python 是用enum 套件來做到枚舉。


Python Enum 語法教學

現在我們用 Python 的 enum 來實作以上範例來當作枚舉語法教學,我想用 enum 來管理代表「職業」的常數成員:

from enum import Enum

class Job(Enum):
    ENGINEER = 1
    PRODUCT_MANAGER = 2
    DATA_SCIENTIST = 3

在此再次提醒 Enumenum 不一樣喔,enum 指的是套件(package),Enum 是其中最常用到的一個類別(Class)。

前面提過,枚舉是在管理一群「成員名稱與成員數值」的對應關係,比如說範例中的 ENGINEER 是成員名稱、1 是它對應的成員數值。在 Python 使用枚舉時,需要創造一個子類別、繼承自 Enum 這個類別,Python 的語法糖讓創造枚舉的子類別變得超級簡單,只要寫上 成員名稱 = 成員數值 即可,成員要增減都十分簡潔。

成員數值使用 int(整數),並且使用序號(照 1、2、3 順序)只是常見的用法,實際上,你為成員數值設計的整數值不一定要照順序(例如 DATA_SCIENTIST = 168)。


現在我們可以用操作類別屬性(Attribute)的方式來操作枚舉與其成員了:

## 枚舉成員的型別正是我們創造的 Enum 子類別
>>> Job.DATA_SCIENTIST
<Job.DATA_SCIENTIST: 3>
>>> type(Job.DATA_SCIENTIST)
<enum 'Job'>

Enum 子類別雖然可以比較是否相等,但是不能比大小。也須注意比較對象究竟是成員名稱還是數值:

## Enum 可以用 == 或 is 比較是否相等
>>> Job.ENGINEER == Job.ENGINEER
True
>>> Job.ENGINEER is Job.ENGINEER
True
>>> Job.ENGINEER != Job.ENGINEER
False
>>> Job.ENGINEER is Job.PRODUCT_MANAGER
False

## 但是不能比大小
>>> Job.ENGINEER < Job.PRODUCT_MANAGER
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'Job' and 'Job'

## 雖然 ENGINEER 確實被賦予數值 1
## 但是「成員」(Enum 子類別)與「成員數值」型別不一樣
## 所以結果當然不可能相等
>>> Job.ENGINEER == 1
False
>>> type(Job.ENGINEER)
<enum 'Job'>
>>> type(1)
<class 'int'>

Enum 資料的操作方式很像是 namedtuple,例如我們創造的 Enum 子類別會有 namevalue 屬性:

>>> Job.DATA_SCIENTIST.name
'DATA_SCIENTIST'
>>> Job.DATA_SCIENTIST.value
3

筆者好豪認為 Enumnamedtuple 好用的地方在於 Enumnamevalue 可以雙向訪問,也就是,使用 namedtuple 通常只能根據 name 取得 value,而 Enum 反過來也做得到:

(這項雙向訪問的特性,本文後續介紹的 pandas + Enum 的運算加速組合技巧 馬上就會用到!)

## 根據 name 取得 value:類別屬性的操作方式
>>> Job.DATA_SCIENTIST
<Job.DATA_SCIENTIST: 3>

## 根據 name 取得 value:像 dict 一樣用字串存取
>>> Job['DATA_SCIENTIST']
<Job.DATA_SCIENTIST: 3>

## 根據 value 也能取得 name
>>> Job(3)
<Job.DATA_SCIENTIST: 3>

可以用 list 來秀出所有枚舉成員,或者用迴圈遍歷整個枚舉:

>>> list(Job)
[<Job.ENGINEER: 1>, <Job.PRODUCT_MANAGER: 2>, <Job.DATA_SCIENTIST: 3>]

>>> for job in Job:
...     print(job)
Job.ENGINEER
Job.PRODUCT_MANAGER
Job.DATA_SCIENTIST

宣告 Enum 子類別後,不包含在枚舉成員中的內容,當然就無法存取囉,換句話說,當你不小心打錯字、或是使用不合理的成員資料時,不用等到程式執行、Python 會在你寫程式的過程(例如在 IDE 介面內)就跟你抱怨!

## 沒有這個成員 -> 程式錯誤!
>>> Job.ACCOUNT_MANAGER
Traceback (most recent call last):
...
AttributeError: ACCOUNT_MANAGER

## 就算成員名稱正確、大小寫不一致也不行 -> 程式錯誤!
>>> Job.Data_Scientist
Traceback (most recent call last):
...
AttributeError: Data_Scientist

## 不存在數值為 42 的成員 -> 程式錯誤!
>>> Job(42)
Traceback (most recent call last):
...
ValueError: 42 is not a valid Job
定義出 Enum 類別後
程式碼打字過程 IDE 會用 Auto-Complete 自己補上可能的成員名稱
不用擔心打錯字、也不怕輸入錯誤的成員名稱
(圖片所用 IDE:Google Colab Notebook

Enum 運用範例:Tensorflow Lite

TensorFlow Lite 是知名的機器學習套件 TensorFlow 的延伸,用於在行動裝置或其他邊緣裝置上部署機器學習模型。

TensorFlow Lite 在定義最佳化(Optimize)選項時,運用了 Python 的 enum 套件。以下是擷取 此 Commit 的簡化版程式碼:

class Optimize(enum.Enum):
    DEFAULT = "DEFAULT"
    OPTIMIZE_FOR_SIZE = "OPTIMIZE_FOR_SIZE"
    OPTIMIZE_FOR_LATENCY = "OPTIMIZE_FOR_LATENCY"
    EXPERIMENTAL_SPARSITY = "EXPERIMENTAL_SPARSITY"

此枚舉主要會被其他函式呼叫的參數設定所用,例如 QuantizationMode 的參數 就用到此枚舉(經些微改寫):

lite.QuantizationMode(
    [lite.Optimize.OPTIMIZE_FOR_LATENCY], 
    lite.TargetSpec(), None, None)

從此案例,我們可以學到兩個使用 enum 的技巧:

  1. 枚舉很適合用在函式呼叫的參數(Parameter)設定,尤其是參數只可能是特定幾種數值時
    • 上述範例中,Tensorflow Lite 需要的最佳化總共只有 4 種,因此用 Enum 來妥善管理這 4 個成員
  2. Enum 的成員數值除了 int(整數)以外,str (字串)也可用

Python Enum 的寫程式慣例

在 Python 程式內使用 enum 時,有一些常見、但是非強制要求的寫程式慣例(Coding Conventions),不遵守這些慣例並不會造成程式出現 bug,但是這些慣例通常也是大多數程式設計師的習慣、所以遵守慣例會讓程式更好讀。在此,筆者好豪分享兩個使用 enum 的慣例:

序號從 1 開始

首先,如果你的成員數值是int(整數)型別、並且需要序號排列(照 1、2、3 順序),建議從 1 開始、而不從 0 開始。其理由是 Python 將 0 視為布林值的 False,但枚舉的成員按理來說,數值都應該要是 True。例如,以下改寫「職業」的枚舉範例、令數值從 0 開始:

class Job(Enum):
    ENGINEER = 0
    PRODUCT_MANAGER = 1
    DATA_SCIENTIST = 2

即使我們妥善設定了成員名稱與數值,從 0 開始的成員數值會出現以下這種詭異的情形:

>>> for job in Job:
...     if job.value:
...         print(job.name)
...     else:
...         print("???")

???
PRODUCT_MANAGER
DATA_SCIENTIST

這當然不是什麼太常見的用法情境,但是為了避免萬一真的發生、又要燒腦找 Bug 的尷尬狀況,我們就乖乖從 1 開始設定成員數值吧。

auto()

既然提到成員數值從 1 開始的話題,我覺得在此很適合介紹另外兩種 enum 套件內宣告 Enum 子類別的做法,因為這兩個做法雖然都不需要明確在程式碼寫出成員數值,但它們都遵從「成員數值從 1 開始」的慣例!

第一,是使用 auto(),如果你對成員數值沒有特別要求,auto() 可以自動幫你創造代替成員數值的實例(Instance)。

from enum import Enum, auto  # 注意 auto 需要額外 import

class Job(Enum):
    ENGINEER = auto()
    PRODUCT_MANAGER = auto()
    DATA_SCIENTIST = auto()

auto() 會自動幫你在成員數值補上 1、2、3 等等整數值:

>>> Job.ENGINEER
<Job.ENGINEER: 1>
>>> list(Job)
[<Job.ENGINEER: 1>, <Job.PRODUCT_MANAGER: 2>, <Job.DATA_SCIENTIST: 3>]

第二,功能性 API 讓你用 Enum( 子類別名稱, 列舉所有成員的字串 ) 的語法來更簡潔地創造枚舉,如下範例:

## Enum( 子類別名稱, 列舉所有成員的字串 )
>>> Job = Enum("Job", "ENGINEER PRODUCT_MANAGER DATA_SCIENTIST")
>>> Job.ENGINEER
<Job.ENGINEER: 1>
>>> list(Job)
[<Job.ENGINEER: 1>, <Job.PRODUCT_MANAGER: 2>, <Job.DATA_SCIENTIST: 3>]

成員名稱全部大寫

第二個建議採用的 enum 寫程式慣例:成員名稱全部都大寫。

枚舉所要管理的是一群常數,而 Python 最重要的寫程式風格指南 PEP8 當中規範,常數的命名需要是全部大寫並且以底線(_)分隔,例如 DATA_SCIENTIST 符合此規範,DataScientist 則不符合。若想知道更多命名慣例以及遵守慣例的好處,我覺得 此表格 相當一目了然。

當然,你不遵守這個命名慣例,enum 程式還是可以運行、不會有 Bug:

class Job(Enum):
    Engineer = 42
    ProductManager = 94666
    DataScientist = 168
>>> Job.DataScientist
<Job.DataScientist: 168>

只不過,如果能遵守慣例的話,閱讀你程式的其他工程師,可以少花一些時間困惑、不用擔心你的程式是否有什麼特殊用意。



三個 Python Enum 進階技巧

學會基礎語法後,我將接著分享自己在實戰中常用到的 Enum 運用技巧。

__str__() 讓常數顯示變美麗

__str__()Enum 支援的其中一種 雙底線方法(Dunder Method),它的功能是幫助你設定 print() 此物件的如何呈現的格式設定。

我們上個小節剛提過 Enum 建議把常數全部用大寫來命名,這項慣例對程式設計師有好處、對程式使用者則不見得,如果你覺得呈現給使用者全部大寫的字串不夠美觀,這時可以用 __str__() 來調整:

class Job(Enum):
    ENGINEER = 1
    PRODUCT_MANAGER = 2
    DATA_SCIENTIST = 3

    def __str__(self):
        return ' '.join([x.capitalize() for x in self.name.split('_')])
## 我個人覺得 "Data Scientist" 比 "DATA_SCIENTIST" 順眼
## 你覺得呢 (´・ω・`)?
>>> print(Job.DATA_SCIENTIST)
Data Scientist

>>> print(f"Wilson is a {Job.DATA_SCIENTIST}.")
Wilson is a Data Scientist.
## 是不是比 "Wilson is a DATA_SCIENTIST."  好看多了?

延伸閱讀:不只 __str__(),Python 還有 許多種「底線」使用方法


unique 避免成員數值重複

在預設狀況下,Enum 不允許重複的成員名稱,程式會出錯:

>>> class Job(Enum):
...     ENGINEER = 1
...     PRODUCT_MANAGER = 2
...     DATA_SCIENTIST = 3
...     DATA_SCIENTIST = 4
...     DATA_SCIENTIST = 5

Traceback (most recent call last):
...
TypeError: Attempted to reuse key: 'DATA_SCIENTIST'

然而,Enum 允許有重複的成員數值,這種作法稱之為別名(Alias)。使用別名的話,相同成員數值的成員在 Enum 內都會被指向同一個成員,因此可能會產生容易令人誤會的結果。

以下範例中,ENGINEERDATA_SCIENTIST 使用相同的成員數值 42,在此情況,在程式碼行數順序中、比較晚宣告的成員都會變成第一個宣告成員的別名,因此,DATA_SCIENTIST 變成了 ENGINEER 的別名,嘗試用 Enum 存取 DATA_SCIENTIST 時,實際取得的卻是 ENGINEER,會讓人感到困惑:

class Job(Enum):
    ENGINEER = 42
    PRODUCT_MANAGER = 2
    DATA_SCIENTIST = 42
>>> Job.ENGINEER
<Job.ENGINEER: 42>
>>> Job.DATA_SCIENTIST
<Job.ENGINEER: 42>
>>> Job.DATA_SCIENTIST.name
'ENGINEER'

承前面所學,auto() 是一個簡單的解法,因為 auto() 不只讓你不用手動輸入成員數值,它自己會產生不重複的成員數值、已經幫你避免別名發生了。

如果你仍需要自己設定成員數值,又不想發生重複成員數值,可以用 unique 裝飾器(Decorator)來禁止別名,使用此裝飾器後,要是 Enum 內發現重複成員數值,會產生 ValueError

## 這段程式碼跟正上方的範例
## 主要差別只有 `@unique` 這一行而已

>>> from enum import Enum, unique # 注意 unique 需要額外 import
>>> @unique
... class Job(Enum):
...     ENGINEER = 42
...     PRODUCT_MANAGER = 2
...     DATA_SCIENTIST = 42

Traceback (most recent call last):
...
ValueError: duplicate values found in <enum 'Job'>: DATA_SCIENTIST -> ENGINEER

補充:即使 unique 禁止重複成員數值,有心人士仍能用繼承子類別的方式「繞過」此禁令,要是你需要嚴格到連子類別繼承都不可使用別名,可以參考官方文件的 DuplicateFreeEnum 作法


Enum 加速 pandas 資料運算

本文曾提及,當你儲存的資料是特定且有限的幾個常數,格外適合使用 Enum,這個情境在資料分析經常出現。以下範例我們創造了有一百萬筆資料的員工每日工作時數資料,其中,職業(job)這行資料,即使有一百萬筆資料、實際上只有 3 種類別:

## 創造範例資料
import pandas as pd
import numpy as np

data_size = 1_000_000
np.random.seed(42)
df = pd.DataFrame()

df['job'] = np.random.choice(['ENGINEER', 'PRODUCT_MANAGER', 'DATA_SCIENTIST'], data_size)
df['age'] = np.random.randint(1, 50, data_size)
df['work_hour'] = np.random.normal(8, 3, data_size)

(如果你沒看過 1_000_000 這種底線用法,這篇 Python 底線教學 有更多說明)

## 快速瀏覽資料
>>> df.head()
              job  age  work_hour
0  DATA_SCIENTIST   32   6.585159
1        ENGINEER   19   1.270486
2  DATA_SCIENTIST   36  10.266954
3  DATA_SCIENTIST   43  10.461590
4        ENGINEER   28  10.306234

## 職業(Job)總共只有 3 種
>>> df['job'].unique()
array(['DATA_SCIENTIST', 'ENGINEER', 'PRODUCT_MANAGER'], dtype=object)

假設,現在我們的資料分析任務是「計算所有員工的平均每日工作時數」,使用 pandas 我們的計算方法只需一行就能完成 df.groupby('job')['work_hour'].mean()。在此小節,我們不在乎這個假想資料的計算結果,我們在乎的是運算所花費的時間

以下,我將使用 Google Colab 裡面超好用的 %timeit 指令 來衡量我們的分析任務需要花費多少時間:

>>> %timeit df.groupby('job')['work_hour'].mean()
58.4 ms ± 9.58 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

這裡可以解讀為:Colab 為我們反覆執行這行分析任務多次,算出平均運算時間是 58.4 毫秒

(延伸閱讀:在 Google Colab 用神奇的「魔法」指令結合 Python 與 Command Line

以上這段分析任務,存在很大的加速空間。資料中的職業(job)明明只有 3 種,卻反覆用 str(字串)型別儲存了一百萬次,事實上很多餘、會對 pandas 造成不必要的負擔。

透過我們在 Enum 學會的做法,我們可以將資料中的職業從 str 轉換成用 int,並用 Enum 妥善管理職業成員以及轉換原則:

class Job(Enum):
    ENGINEER = 1
    PRODUCT_MANAGER = 2
    DATA_SCIENTIST = 3

    def __str__(self):
        return ' '.join([x.capitalize() for x in self.name.split('_')])

我們將範例資料中的職業欄位用 Enum 轉換成 int 型態:

>>> df['job'] = df['job'].apply(lambda x: Job[x].value)
>>> df.head()
   job  age  work_hour
0    3   32   6.585159
1    1   19   1.270486
2    3   36  10.266954
3    3   43  10.461590
4    1   28  10.306234

現在,我們再次用 Colab 中的 %timeit 指令來重新衡量計算時間,看看分析任務運算速度是否有變化:

>>> %timeit df.groupby('job')['work_hour'].mean()
11.1 ms ± 130 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

分析任務的平均運算時間變成了 11.1 毫秒。跟剛剛的 58.4 毫秒相比,我們可以說,透過 Enum 把職業欄位從 str 轉換成 int 型別後,計算速度加快了 5 倍之多!

千萬別覺得只有幾毫秒之差乍看之下不多,在職場實戰中,遇到資料庫動輒幾十億筆的資料,如果可以做到這般計算最佳化,可能讓你省下好幾小時的計算時間!

做了轉換後,你又或許會覺得資料不太美觀,例如,看不出來 1、2、3 分別代表什麼職業。其實只要應用這則筆記 前面提到namevalue 雙向訪問,很輕易地就能把資料轉換回好閱讀的格式:

## 看不出來 1、2、3 代表什麼職業
>>> df.groupby('job')['work_hour'].mean()
job
1    7.989738
2    8.006799
3    8.000956
Name: work_hour, dtype: float64

## 用 Job(2) 這種語法就能簡單地轉換回來
>>> result_df = df.groupby('job')['work_hour'].mean().reset_index()
>>> result_df['job'] = result_df['job'].apply(lambda x: str(Job(x)))
>>> result_df
               job  work_hour
0         Engineer   7.989738
1  Product Manager   8.006799
2   Data Scientist   8.000956

(小細節:稍早宣告 Enum 子類別時有寫出 __str__(),才得以讓這裡轉換的字串更美觀喔)


補充:

讀到這裡的你如果已經有些數據分析經驗了,也許會察覺,若目標是把職業欄位從 str 轉換成 int,用 dict 就能輕易達成了,像是寫成:{'ENGINEER': 1, ...}。沒錯,光是這麼做的確能夠達成跟前面一樣讓 pandas 加速運算 5 倍的效果。

不過,比起 dict,使用 Enum 的還有額外好處,包括:

  1. 當你需要再從 int 轉換回 str 時,不需要另外創造一個 {1: 'ENGINEER', ...}dict
  2. Enum 的成員管理更嚴謹,本文提過的避免輸入錯字與無效成員等好處,可以讓你的資料工作流(Data Pipeline)更加強健、不容易出錯,程式碼也更好維護

但缺點是 Enum 要寫的程式碼比 dict 稍微多一點。


結語

使用 Python 的 enum 套件來達成枚舉,幫助你更好管理一群「成員名稱與成員數值」的對應關係,當你需要管理的常數值集合數量有限的情境,Enum 相當好用。只要搭配好常數命名大寫、還有成員數值序號從 1 開始等慣例,enum 最大的優點是讓你的程式可讀性更高,減少 Bug 出現率。

最後,使用 Enum 的時機還是需要權衡的,當然不是任何用到常數的場合都適合用 Enum。我認為,只有你的程式設計到了重視可讀性與程式碼品質的階段時,多打幾行程式設計 Enum 子類別才有效益,舉例來說,如果你的工作是探索資料,既不在乎運算速度、也不在乎結果的 可重現性、程式碼也不需要版本控制,這種時候也不見得需要多寫 Enum 來處理。

參考資料:


還想知道更多 Python 相關技巧嗎?推薦你閱讀好豪的其他 Python 分享文章,學會更多實用程式設計方法:

也感謝你閱讀這篇筆記,歡迎追蹤 好豪的粉絲專頁,我會持續分享 Python 技巧、資料科學等知識;歡迎點選下方按鈕將本文加入書籤、或者分享給更多正在學 Python 的朋友。

推薦閱讀