直接用数字常量(如 status == 2)导致业务语义不明确,维护困难;应使用 Enum(如 Status.APPROVED)显式表达意图,优选纯 Enum,避免魔法数字,注意值类型统一、禁止重复值、妥善处理序列化与全链路同步。

为什么直接用数字常量会让后续维护变困难
魔法数字(比如 0、1、2)出现在条件判断或赋值中时,没人能一眼看懂它代表什么业务含义。比如 status == 2,是“已取消”?“待审核”?还是“已归档”?改代码的人得翻遍注释或数据库字段定义才能确认,一不小心就改错。
用 Enum 不是为了炫技,而是把隐含的业务语义显式暴露出来——让 Status.CANCELLED 这种写法本身就能说清意图。
怎样正确定义和使用 Enum 类型
别直接继承 int 或 str,除非你明确需要兼容旧接口;标准做法是继承 Enum 或 IntEnum(后者允许与整数比较,但会削弱类型安全)。最稳妥的是纯 Enum:
from enum import Enum
class Status(Enum):
PENDING = 1
APPROVED = 2
CANCELLED = 3
使用时必须用枚举成员,不能用原始数字:
立即学习“Python免费学习笔记(深入)”;
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
- ✅ 正确:
if order.status == Status.APPROVED: - ❌ 危险:
if order.status == 2:—— 绕过类型检查,IDE 和 mypy 都拦不住 - ⚠️ 注意:
Status(2)能反查到Status.APPROVED,但这是运行时行为,不该作为主要访问方式
Enum 成员值选整数还是字符串?
值类型影响序列化、数据库映射和调试体验:
- 用整数(如
PENDING = 1):适合已有数据库字段是 tinyint 的场景,ORM 映射简单,但日志里只显示1,不直观 - 用字符串(如
PENDING = "pending"):日志和 API 返回更可读,但要注意大小写和拼写一致性;若需存入整型字段,得额外加转换逻辑 - 避免混合类型:同一个枚举里不要有的用数字、有的用字符串,会导致
isinstance判断失效
如果要兼顾可读性和存储效率,可以用 auto() 配合自定义 __str__ 或 name/value 属性暴露不同形式。
常见踩坑点:== vs is,以及 JSON 序列化失败
两个枚举成员值相同(比如 A = 1, B = 1),用 == 会返回 True,但它们不是同一个对象 —— 这容易引发逻辑误判。Python 默认允许重复值,但你应该禁用:
from enum import Enum, unique
@unique
class Role(Enum):
ADMIN = 1
USER = 2
JSON 序列化会报错:TypeError: Object of type Role is not JSON serializable。解决方法不是手动转 .value,而是统一用 dataclasses 或自定义 json.JSONEncoder 处理,或者提前在模型层做转换(例如 ORM 的 hybrid_property 返回 .name)。
真正麻烦的不是定义枚举,而是所有用到该字段的地方——数据库迁移、API 输入校验、前端下拉选项、测试 mock 数据——都得同步更新。漏掉一处,就等于白改。

















