Python 的 Enum:别再让散落的字符串常量满天飞
Python 的 Enum:别再让散落的字符串常量满天飞
写 Python 代码时,最容易悄悄长出来的技术债,就是散落在各处的字符串常量:"pending"、"paid"、"shipped",今天在订单模块写一遍,明天在报表里又写一遍。拼错一个字母不会报错,只会在运行时悄悄走错分支,等发现时往往已经是一笔错账。
Enum 正是用来收拢这些常量的:把一组相关的取值收进一个类型里,让拼写错误在写代码时就暴露出来。
from enum import Enum
class OrderStatus(Enum):
PENDING = "pending"
PAID = "paid"
SHIPPED = "shipped"
这样一来,代码里不再直接写 "paid",而是写 OrderStatus.PAID。写错成 OrderStatus.PAIID 会立刻报 AttributeError,编辑器也能自动补全;写错字符串却什么提示都没有,只能靠测试或线上事故发现。
第二个好处是比较更安全。字符串比较靠的是值相等,"Paid" 和 "paid" 就不是同一个状态,大小写一混就出问题。枚举成员是单例,is 比较就够了:
if order.status is OrderStatus.PAID:
send_receipt(order)
第三个要点是取值与展示要分开。枚举成员的 .value 是存进数据库或发给接口的值,.name 是代码里的名字,两者不必相同:
class OrderStatus(Enum):
PENDING = "pending"
print(OrderStatus.PENDING.value) # pending
print(OrderStatus.PENDING.name) # PENDING
入库时存 .value,读出来再用 OrderStatus(value) 还原成成员;如果库里出现了一个不在枚举里的旧值,OrderStatus(value) 会直接报 ValueError,这反而是好事——脏数据在边界就被拦住,而不是带着一个谁也不认识的状态一路往下跑。
还有一个实用技巧:需要按顺序比较的状态,可以用 IntEnum,让成员同时是一个整数:
from enum import IntEnum
class Priority(IntEnum):
LOW = 1
NORMAL = 2
HIGH = 3
assert Priority.HIGH > Priority.LOW
但要注意,IntEnum 的成员和整数可以直接比较、也可以混进算术运算,这既是方便也是口子:不希望被当成数字用的状态,就老老实实用普通的 Enum,别为了图省事都换成 IntEnum。
最后说一个常见坑:不要在枚举成员里放可变对象,也不要给枚举加太多行为。枚举的职责是“把取值收拢、把名字定死”,状态流转的规则——比如已发货的订单能不能退回待支付——应该写在单独的函数里,而不是塞进枚举的方法中,否则枚举很快又会变成另一个什么都管的大类。
总结一下:字符串常量适合只出现一次的临时值,一旦某个取值会在两个以上的地方出现,就把它收进 Enum;比较用 is,入库用 .value,读库用 OrderStatus(value) 还原并让非法值尽早报错。把名字定死,拼写错误就从运行时事故变成了写代码时的即时提醒。
- 点赞
- 收藏
- 关注作者
评论(0)