
当类同时继承 str 和 enum.Enum 时,实例在字符串拼接中表现如普通字符串(输出 "NEW"),而在 print 中则按枚举格式显示(输出 "Status.NEW"),根源在于 __add__ 和 __str__ 方法分别继承自不同父类。
当类同时继承 str 和 enum.enum 时,实例在字符串拼接中表现如普通字符串(输出 "new"),而在 print 中则按枚举格式显示(输出 "status.new"),根源在于 `__add__` 和 `__str__` 方法分别继承自不同父类。
在 Python 中,class Status(str, enum.Enum) 构建了一个多重继承类:它既是字符串(str)又是枚举成员(enum.Enum)。这种设计看似便捷,却隐含行为不一致的风险——关键在于 Python 方法解析顺序(MRO)与不同操作触发的特殊方法来源不同。
首先看字符串拼接:
print("" + Status.NEW) # 输出: "NEW"
此处 + 运算符调用 Status.NEW.__add__。由于 str 在 MRO 中排在 enum.Enum 之前(Status.__mro__ 为 (Status, str, enum.Enum, object)),str.__add__ 被选用,而该方法直接返回拼接后的字符串,忽略枚举身份,仅使用其底层字符串值 "NEW"。
再看直接打印:
print(Status.NEW) # 输出: "Status.NEW"
print() 内部调用 str(obj),进而触发 obj.__str__()。虽然 str 类定义了 __str__,但 enum.Enum 重写了 __str__(返回 f"{self.__class__.__name__}.{self.name}")。根据 MRO,enum.Enum.__str__ 优先于 str.__str__ 被继承(因 enum.Enum 在 str 之后、且 __str__ 是显式覆盖),因此输出为 "Status.NEW"。
⚠️ 注意事项:
这种行为不是 bug,而是多重继承下方法解析的自然结果,但极易引发混淆;
-
避免手动组合
str与enum.Enum;推荐使用 Python 3.11+ 内置的enum.StrEnum:import enum class Status(enum.StrEnum): NEW = "NEW" EXCLUDED = "EXCLUDED" print("" + Status.NEW) # "NEW" print(Status.NEW) # "NEW"(StrEnum.__str__ 返回纯字符串) print(repr(Status.NEW)) # Status.NEW(保留枚举标识) StrEnum本质是str+Enum的安全封装,其__str__明确返回self.value,而__repr__保持枚举语义,兼顾可读性与一致性。
总结:多重继承需谨慎权衡——若需“字符串即值”的语义,优先选用 StrEnum;若必须自定义混合类,应显式重写 __str__、__repr__ 等关键方法,确保行为可预测。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











