intenum 比 enum 快在整数比较而非对象身份比对:intenum 成员是 int 实例,== 直接调用 c 层整数比较;enum 成员是独立对象,== 触发 eq 方法调用,有属性查找和逻辑开销。

IntEnum 比 Enum 快在哪?本质是整数比较而非对象身份比对
当你用 Enum 定义成员(比如 class Color(Enum): RED = 1; BLUE = 2),每个成员都是独立对象,== 比较实际触发的是 __eq__ 方法调用,涉及属性查找和逻辑判断;而 IntEnum 继承自 int,成员本身就是整数——== 直接走 C 层整数比较,无函数调用开销。在高频循环或条件判断中(如解析协议字段、状态机跳转),这个差异会明显放大。
- 典型场景:每秒处理数万条日志,需频繁比对
status字段是否等于Status.ERROR - 实测差异:在 Python 3.11 下,
IntEnum成员比较比普通Enum快 3–5 倍(基于timeit测量a == b) - 注意:只有
==、!=、等数值运算符才享受整数加速;<code>is判断仍依赖单例性,两者行为一致
什么时候不能直接换 IntEnum?小心类型隐式转换陷阱
IntEnum 的“整数性”是一把双刃剑:它允许与 int 直接比较(Status.OK == 0 返回 True),但也意味着可能意外绕过类型检查,掩盖逻辑错误。
- 常见坑:数据库读出的整数
row["status"]直接和Status.OK比较,看似正常,但若数据脏(比如存了 -1 或 999),Status(-1)会被动态构造,不报错却产生非法枚举实例 - 安全做法:显式用
Status(row["status"])构造,并捕获ValueError;或改用Status._value2member_map_.get(val)做查表(返回None而非抛异常) - Pydantic / dataclass 场景:若字段声明为
Status类型,传入纯数字会触发验证失败——此时IntEnum反而更严格,不是缺陷而是保护
性能敏感路径下,用 _value2member_map_ 替代遍历 name 查找
即使用了 IntEnum,若你常做 “已知值找成员”(比如从 JSON 整数还原枚举),别写 next((s for s in Status if s.value == x), None)——这是 O(n) 遍历。所有 IntEnum(及 Enum)都预建了 _value2member_map_ 字典,支持 O(1) 查找。
status = Status._value2member_map_.get(x)
if status is None:
raise ValueError(f"Invalid status value: {x}")
-
_value2member_map_是私有属性,但稳定存在于 CPython 所有 3.6+ 版本,被官方文档隐式推荐用于高性能查找 - 不要用
getattr(Status, "name")反向查——这依赖字符串名,且大小写/拼写必须完全匹配 - 如果值域稀疏(比如只定义了 1、2、1000),该字典仍只存已定义项,内存友好
别忽略 __members__ 和 __members__.keys() 的开销
想列出所有枚举名?避免写 list(Status.__members__) 或 Status.__members__.keys() 在热循环里——每次访问 __members__ 都会重建 MappingProxyType 对象,带来额外分配和 GC 压力。
- 正确姿势:启动时缓存
STATUS_NAMES = tuple(Status.__members__),后续直接复用 - 若只需判断是否存在某个 name,用
"OK" in Status.__members__是高效的(底层走哈希查找) - 注意:
__members__包含所有定义的成员,包括那些被@enum.unique拦截的重复项(它们不会出现在_value2member_map_中)
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











