Python Enum 类(带 tostring 和 fromstring)

10 投票
7 回答
23376 浏览
提问于 2025-04-16 08:41

我找到了一种简单的方法,可以在Python中实现(或者说是“黑客”)枚举(enum):

class MyEnum:
  VAL1, VAL2, VAL3 = range(3)

然后我可以这样调用它:

bob = MyEnum.VAL1

太酷了!

好吧,现在我想要能够根据字符串获取数字值,或者根据数字值获取字符串。假设我希望字符串能够和枚举的键完全匹配。

我能想到的最好办法是这样的:

class MyEnum:
  VAL1, VAL2, VAL3 = range(3)
  @classmethod
  def tostring(cls, val):
    if (val == cls.VAL1):
      return "VAL1"
    elif (val == cls.VAL2):
      return "VAL2"
    elif (val == cls.VAL3):
      return "VAL3"
    else:
      return None
  @classmethod
  def fromstring(cls, str):
    if (str.upper() == "VAL1"):
      return cls.VAL1
    elif (str.upper() == "VAL2"):
      return cls.VAL2
    elif (str.upper() == "VAL2"):
      return cls.VAL2
    else:
      return None

或者类似的东西(忽略我如何处理无效情况)

有没有更好、更符合Python风格的方法来做我上面提到的事情?还是说上面的方式已经足够简洁了。

感觉应该有更好的方法来实现这个。

7 个回答

7

使用字典:

MyEnum = {'VAL1': 1, 'VAL2':2, 'VAL3':3}

不需要用到类。字典比类更好,因为1.) 它们非常高效,2.) 内置了很多强大的方法,3.) 是一种通用的语言结构。字典也可以扩展:

MyEnum['VAL4'] = 4

在Python中实现C++(或其他语言)的功能并不是明智的选择。如果你发现自己在“搞一个枚举”之类的事情,那你可以肯定,这不是Python的做法。

如果你想反过来做,可以再创建一个字典。(例如 {'1':'VAL1', ...}

23

[时间在流逝...]

新的 Python 枚举(Enum)功能终于在 3.4 版本中推出了,并且也可以在旧版本中使用。所以现在你可以使用这个功能来解决你的问题。 :)


下面是一个例子:

>>> from enum import Enum
>>> class Modes(Enum) :
...    Mode1 = "M1"
...    Mode2 = "M2"
...    Mode3 = "M3"
...

>>> Modes.Mode1
<Modes.Mode1: 'M1'>

>>> Modes.Mode1.value
'M1'

>>> Modes.Mode1.value
'M1'

>>> Modes['Mode1']    # index/key notation for name lookup
<Modes.Mode1: 'M1'>

>>> Modes('M1')       # call notation for value lookup
<Modes.Mode1: 'M1'>

>>> Modes("XXX")      # example error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Anaconda3\lib\enum.py", line 291, in __call__
    return cls.__new__(cls, value)
  File "C:\Anaconda3\lib\enum.py", line 533, in __new__
    return cls._missing_(value)
  File "C:\Anaconda3\lib\enum.py", line 546, in _missing_
    raise ValueError("%r is not a valid %s" % (value, cls.__name__))
ValueError: 'XXX' is not a valid Modes
11

好的,这里是你要的内容:

class MyEnum:
  VAL1, VAL2, VAL3 = range(3)
  @classmethod
  def tostring(cls, val):
    for k,v in vars(cls).iteritems():
        if v==val:
            return k

  @classmethod
  def fromstring(cls, str):
      return getattr(cls, str.upper(), None)

print MyEnum.fromstring('Val1')
print MyEnum.tostring(2)

不过,我真的不明白Python中枚举(Enums)的意义。Python本身有丰富的类型系统,还有生成器和协程来管理状态。

我知道我在Python中已经有超过12年没用过枚举,也许你也可以不需要它们 ;-)

撰写回答