aenum.Enum中__str__返回结果触发__init__调用的原因咨询
咱们来一步步拆解你这段基于aenum的代码里的问题,以及你遇到的无法理解的行为根源:
1. 继承顺序的核心问题
你定义的MyEnum继承顺序是str, Enum,这本身就违背了Enum类的设计规范。对于Python的Enum(包括aenum),正确的继承顺序应该是Enum在前,数据类型在后,也就是Enum, str。因为Enum是由元类控制的特殊类,先继承普通数据类型会干扰Enum元类对成员的初始化逻辑,导致内部状态混乱。
2. 错误的__new__方法实现
你重写的__new__方法完全绕过了aenum的初始化逻辑:
def __new__(cls, name, *args, **kwargs): member = str.__new__(cls) member._value_ = name return member
结合你设置的settings=AutoValue和init="value data1 data2",aenum本来会自动处理成员值的生成(AutoValue),并把data1、data2作为成员的额外属性。但你的__new__直接用str.__new__创建实例,还强行把_value_设为成员名称name,这直接破坏了aenum的内部机制,导致成员的真实值、额外数据都无法被正确初始化,自然会出现预期外的行为。
3. __str__赋值的无限递归风险
你把__str__设为lambda self: self,这会引发无限递归:当调用str(self)时,会触发__str__方法,而该方法返回self,Python又会尝试把self转为字符串,再次调用__str__,陷入循环。不过因为前面的__new__和继承问题,可能没有直接抛出递归错误,但会导致成员的字符串表现完全不符合预期。
正确的实现思路
如果你想让MyEnum的成员是字符串类型,且自定义__str__行为,应该这样写:
from aenum import Enum, AutoValue class MyEnum(Enum, str, settings=AutoValue, init="value data1 data2"): def __str__(self): # 这里可以返回你想要的字符串,比如成员值、名称或自定义内容 return self._value_ # 如果需要自定义成员初始化,不要完全绕过aenum逻辑 def __new__(cls, value, data1, data2): member = str.__new__(cls, value) member._value_ = value member.data1 = data1 member.data2 = data2 return member # 示例成员定义 Foo = ("foo_val", "foo_data1", "foo_data2") Bar = ("bar_val", "bar_data1", "bar_data2")
这样既保证了Enum的正常工作,又实现了自定义的字符串表现,同时保留了aenum的AutoValue和额外数据功能。
内容的提问来源于stack exchange,提问作者W. B. Reed

