应使用@unique装饰器强制枚举值唯一并禁止别名,因其在定义时即校验重复值并抛出valueerror;普通enum允许不同名称映射相同值,导致类型检查失效、序列化暴露别名等隐患。

直接用 Enum 类定义枚举,就能获得类型安全、不可变、可迭代、支持成员比较的常量集合——但多数人漏掉了 unique 和 verify 装饰器,导致重复值被静默接受,埋下运行时隐患。
为什么不能只继承 Enum 就完事?
默认的 Enum 允许不同名字映射到相同值,比如 RED = 1 和 CRIMSON = 1 会共存,但它们在类型检查和逻辑判断中被视为同一成员,容易引发意外交互。
- 类型检查器(如 mypy)对普通
Enum的判等行为不报错,但实际语义上不该等价 -
list(MyEnum)会包含所有项,包括“别名”,而你通常只想要主成员 - 序列化(如 JSON)或日志打印时,别名可能意外暴露,破坏接口契约
怎么强制枚举值唯一且禁止别名?
用 @unique 装饰器是最小代价的防护手段,它在类定义时就抛出 ValueError,而不是等到运行时才发现冲突。
from enum import Enum, unique <p>@unique class Status(Enum): PENDING = 1 PROCESSING = 2 DONE = 3</p><h1>CRIMSON = 1 ← 这里会触发 ValueError: duplicate values found</h1><p></p>
- 必须加在类定义上方,不是函数调用;不加则无校验
- 仅检查值重复,不校验名称重复(名称重复本身语法就不允许)
- 与
IntEnum或StrEnum(Python 3.11+)兼容,但需注意StrEnum自带@unique行为
如何让枚举支持 JSON 序列化和数据库存储?
直接 json.dumps(enum_member) 会报 TypeError,因为枚举成员不是原生 JSON 类型;常见做法是显式取 .value 或 .name,但更稳妥的是统一实现 __str__ 和 __repr__,并提供 to_dict() 方法。
- 避免重写
__dict__或依赖dataclasses.asdict,枚举没有字段属性 - 推荐在基类里封装:继承自
Enum的子类统一用member.value存库、member.name做日志标识 - 若需反序列化,别用
Status['PENDING'](键不存在时报KeyError),改用Status._member_map_.get('PENDING')或封装安全获取函数
什么时候该用 IntEnum 或 StrEnum?
当枚举值要参与数值计算或字符串拼接时,选对应子类;否则坚持用普通 Enum,防止隐式类型转换引入 bug。
-
IntEnum:值是 int,能和数字比较(Status.PENDING == 1成立),适合状态码映射 -
StrEnum(3.11+):值是 str,支持+拼接和.lower()等方法,适合 API 字段名或配置键 - 混用风险高:比如
IntEnum成员和int比较看似方便,但isinstance(x, int)返回True,可能绕过类型检查
真正难的不是定义枚举,而是让团队一致使用 .value 存储、.name 调试、@unique 校验,并在 ORM 映射和 API 层明确约定序列化协议——这些地方一松动,类型安全就形同虚设。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











