有人在杯型欄裡打了「中懷」,查價直接落空。如果一開始就只允許固定的幾個名字,這個錯誤在門口就會被攔下。為什麼 Enum 比裸字串安全?
Enum 為一組固定的命名值提供真正的型別。成員是唯一物件,比到處傳遞裸字串更容易比較和驗證。需要顯示或序列化時,還能分別取得名稱和值。 你還會把 auto 值留在內部、組合權限,並驗證儲存值。
定義命名成員
繼承 Enum,並給名字賦值。Color.RED 是成員物件,不是字串 "red"。用 .name 取得標識符,用 .value 取得底層值。成員之間按身份比較。
from enum import Enum
class Color(Enum):
RED = "red"
GREEN = "green"
print(Color.RED.value)
print(Color.RED.name)有穩定值的名字
走訪成員
Enum 類可以按定義順序走訪。它適合建構選單、驗證選項和生成文件。走訪產生的是成員物件,不是原始值。
from enum import Enum
class Color(Enum):
RED = "red"
GREEN = "green"
for color in Color:
print(color.name, color.value)一組固定的選擇
按值或按名稱尋找
用值呼叫列舉會回傳對應成員,找不到時拋出 ValueError。方括號按成員名稱尋找,名稱不存在時拋出 KeyError。根據輸入來源選擇正確的尋找方式。
from enum import Enum
class Color(Enum):
RED = "red"
GREEN = "green"
print(Color("green"))
print(Color["RED"])兩種尋找方式
auto() 的值只是實現細節
auto() 會分配連續整數,程式內部用很方便,但不適合持久化。插入新成員時這些數字可能改變。@unique 能抓住意外別名,也就是兩個名字拿到同一個值的情況。
from enum import Enum, auto, unique
@unique
class Stage(Enum):
NEW = auto()
PAID = auto()
SHIPPED = auto()
print([(stage.name, stage.value) for stage in Stage])
print(Stage.PAID is Stage(2))名字穩定,auto 數字只在本程式內有效
用 Flag 組合權限
Flag 成員是可以按位組合的位值。檢查權限時,用按位與再和該權限比較,不要直接比較整個組合值。只有在邊界格式有明確文件時,才儲存組合後的整數。
from enum import Flag, auto
class Permission(Flag):
READ = auto()
WRITE = auto()
ADMIN = READ | WRITE
editor = Permission.READ | Permission.WRITE
print(editor)
print((editor & Permission.READ) == Permission.READ)
print((editor & Permission.ADMIN) == Permission.ADMIN)小型權限集合用位標誌
存值,讀回時再驗證
Enum 成員不是 JSON 值。在邊界存 member.value,讀回時呼叫列舉類,既驗證又還原成員。未知值會拋出 ValueError,這正是我們想要的失敗,而不是悄悄接受拼字錯誤。
from enum import Enum
class Plan(Enum):
FREE = "free"
PRO = "pro"
payload = {"plan": Plan.PRO.value}
restored = Plan(payload["plan"])
print(restored.name, restored.value)
try:
Plan("team")
except ValueError as error:
print(type(error).__name__, error)儲存用值,程式碼裡用成員
本課要點
- Enum 成員是帶名稱和值的唯一物件。
- 用 .name 和 .value 分別存取名稱和值。
- 走訪會按定義順序產生成員。
- Color(value) 按值尋找;Color[name] 按名稱尋找。
- 無效尋找會按方式不同拋出 ValueError 或 KeyError。
- 不要持久化 auto 值;組合狀態用 Flag;讀回儲存值時讓列舉類驗證。
常見錯誤
- 把列舉成員和它的原始值直接比較,並期待相等。
- 需要封閉選項集合時,仍然使用裸字串。
- 混淆按值尋找和按名稱尋找。
- 把 Enum 成員直接寫進 JSON,以為它會自動變成對應的值。
定義帶 RED 和 GREEN 的 Color 列舉,列印 Color.RED.value,再尋找 Color('green')。
動手試試
改改變數、先預測輸出,再執行程式碼。第一次點擊「執行程式碼」時會下載 Python 執行時,可能需要幾秒鐘。
練習本課
12 道題,作答後立即看到解釋。