我刚刚发现 python 中存在 Enum 基类,我正在尝试想象它对我有何用处。
假设我定义了交通灯状态:
from enum import Enum, auto
class Signal(Enum):
red = auto()
green = auto()
orange = auto()
假设我从程序中的某个子系统接收信息,以表示颜色名称的字符串形式,例如
brain_detected_colour = "red"
。
如何将此字符串与交通灯信号进行比较?
显然,
brain_detected_colour is Signal.red
是False
,因为Signal.red
不是字符串。
Signal(brain_detected_colour) is Signal.red
失败,并显示 ValueError: 'red' is not a valid Signal
。
人们不会创建枚举的实例。
Signal(foo)
语法用于按值访问 Enum 成员,当它们是 auto()
时不打算使用它们。
但是,可以使用字符串访问枚举成员,就像使用方括号访问
dict
中的值一样:
Signal[brain_detected_colour] is Signal.red
另一种可能性是将字符串与 Enum 成员的
name
进行比较:
# Bad practice:
brain_detected_colour is Signal.red.name
但是在这里,我们不是测试 Enum 成员之间的身份,而是比较字符串,因此最好使用相等测试:
# Better practice:
brain_detected_colour == Signal.red.name
(字符串之间的身份比较之所以有效,要归功于 string interning,最好不要依赖它。感谢 @mwchase 和 @Chris_Rands 让我意识到这一点。)
另一种可能性是在创建枚举时显式地将成员值设置为其名称:
class Signal(Enum):
red = "red"
green = "green"
orange = "orange"
(请参阅此答案,了解自动执行此操作的方法。)
那么,
Signal(brain_detected_colour) is Signal.red
就有效了。
更好的做法是从
Signal
继承str
:
class Signal(str, Enum):
red = 'red'
green = 'green'
orange = 'orange'
brain_detected_colour = 'red'
brain_detected_colour == Signal.red # direct comparison
可以让
auto()
返回枚举成员的名称作为其值(位于文档的 auto
部分1:
class AutoName(Enum):
def _generate_next_value_(name, start, count, last_values):
return name
class Ordinal(AutoName):
NORTH = auto()
SOUTH = auto()
EAST = auto()
WEST = auto()
使用中:
>>> list(Ordinal)
[<Ordinal.NORTH: 'NORTH'>, <Ordinal.SOUTH: 'SOUTH'>, <Ordinal.EAST: 'EAST'>, <Ordinal.WEST: 'WEST'>]
1 这需要 Python 3.6 版本,或
aenum
2.02(aenum
适用于 2.7 之前的 Python)。
2 披露:我是 Python stdlib
Enum
、enum34
向后移植 和 高级枚举 (aenum
) 库的作者。
class Signal(Enum):
red = auto()
green = auto()
orange = auto()
def equals(self, string):
return self.name == string
brain_detected_colour = "red"
if Signal.red.equals(brain_detected_colour):
#something awesome
从 Python 3.11 开始,您可以使用 StrEnum https://docs.python.org/3/library/enum.html#enum.StrEnum
from enum import StrEnum
class Signal(StrEnum):
red = auto()
green = auto()
orange = auto()
然后完全按照你想要的方式使用
>>> "red" == Signal.red
True
>>> "orange" == Signal.red
False