如何创建一个以成员名称为值的枚举?

3 投票
2 回答
2980 浏览
提问于 2025-04-18 09:48

我想简化下面这个类,这样我就不需要为每个元素都输入值,而是可以直接使用枚举成员的名字。这有点像文档中的AutoNumber示例

class Screen(Enum):
    MAIN = 'main'
    OPTIONS = 'options'
    GAME = 'game'
    SCORE = 'score'

我想用下面的方式来实现,比如说Screen.MAIN的值是'main'

class Screen(AutoNameValueEnum):
    MAIN = ()
    OPTIONS = ()
    GAME = ()
    SCORE = ()

我尝试修改链接中的示例,但我搞不清楚怎么才能获取枚举成员的名字。

2 个回答

4

更新

在Python 3.6和aenum 2.0中,新增了一种方法,可以让你自定义枚举成员的值,这样做起来就简单多了:

def _generate_next_value_(name, start, count, last_values):
    return name
  • name是成员的名字
  • start是枚举的起始值(默认是1
  • count是目前为止成员的数量
  • last_values是到目前为止成员的值的列表

你不能通过class方法来实现这一点,但可以使用功能性API来做到:

Color = enum.Enum(
    'Color',
    ((name, name.lower()) for name in 'BLACK RED GREEN BLUE'.split()),
    )

*好吧,像Python中的大多数事情一样,如果你足够努力,确实可以做到,但何必费那么大劲呢?

4

在一个Enum(枚举)中,成员本身也是Enum。文档中的例子使用了成员的__new__方法来给它们赋值。不过,你不能用这个方法,因为新的成员并不知道它是如何在它所属的类中被调用的。相反,你应该使用初始化器。下面是一个例子:

>>> class AutoNameValueEnum(enum.Enum):
...    def __init__(self):
...        self._value_ = self._name_.lower()
...
>>> class Color(AutoNameValueEnum):
...    RED = ()
...
>>> Color.RED
<Color.RED: 'red'>

更新:

请注意,使用这个解决方案后,值的查找将不再可能。这是因为枚举的元类在调用初始化器之前就存储了值。这会导致你无法将枚举进行序列化,也可能在其他地方出现问题。一个替代方案(虽然会破坏与类似字符串的等价性,比如a is "foo",但其他方面不会受影响)是使用不可哈希的类型作为值。这样,枚举类就会进行线性搜索,而不是通过映射查找值的键。

class UnhashableString(str):
    def __hash__(self):
        raise TypeError

class AutoNameValueEnum(enum.Enum):
    def __init__(self):
        self._value_ = UnhashableString(self._name_.lower())

class Color(AutoNameValueEnum):
    RED = ()

这是这个替代方案的更新例子。总的来说,我认为使用这里建议的功能接口是最干净的解决方案,因为你可以确保在使用它时不会出现问题。

撰写回答