这个问题在这里已经有了答案:
Python Enum, when and where to use?
(1 个回答)
5年前关闭。
在 Python 3.4 中,我们在标准库中得到了一个 Enum 库:enum
.我们可以获得 enum
的反向移植适用于 Python 2.4 到 2.7(甚至 3.1 到 3.3),enum34在皮皮。
但是我们在没有这个新模块的情况下已经相处了很长一段时间 - 那么为什么我们现在有了它?
我对来自其他语言的枚举的目的有一个大致的了解。在 Python 中,通常使用如下的裸类并将其称为枚举:
class Colors:
blue = 1
green = 2
red = 3
这可以在 API 中用于创建值的规范表示,例如:
function_of_color(Colors.green)
如果这有任何批评,它是可变的,你不能迭代它(容易),我们如何知道整数的语义,
2
?然后我想我可以使用像命名元组这样的东西,它是不可变的?
>>> Colors = namedtuple('Colors', 'blue green red')
>>> colors = Colors('blue', 'green', 'red')
>>> colors
Colors(blue='blue', green='green', red='red')
>>> list(colors)
['blue', 'green', 'red']
>>> len(colors)
3
>>> colors.blue
'blue'
>>> colors.index(colors.blue)
0
namedtuple 的创建有点多余(我们必须将每个名称写两次),因此有些不雅。获取颜色的“编号”也有点不雅(我们要写
colors
两次)。值检查必须用字符串来完成,这样效率会低一些。所以回到枚举。
枚举的目的是什么?他们为语言创造了什么值(value)?我什么时候应该使用它们,什么时候应该避免它们?
最佳答案
What's the purpose of enums? What value do they create for the language? When should I use them and when should I avoid them?
Enum 类型通过 PEP 435 进入 Python .给出的理由是:
The properties of an enumeration are useful for defining an immutable, related set of constant values that may or may not have a semantic meaning.
为此目的使用数字和字符串时,它们的特征可以是 "magic numbers"或“魔术弦”。数字很少带有语义,字符串很容易混淆(大写?拼写?snake 或camel-case?)
星期几和学校字母等级是这种值集合的例子。
这是来自 docs 的示例:
from enum import Enum
class Color(Enum):
red = 1
green = 2
blue = 3
与裸类一样,这比 namedtuple 示例更具可读性和优雅性,它也是不可变的,并且我们将在下面看到它的更多好处。严格占优:枚举成员的类型是枚举
>>> type(Color.red)
<enum 'Color'>
>>> isinstance(Color.green, Color)
True
这允许您定义枚举定义中成员的功能。可以使用其他先前的方法来定义值的功能,但这会非常不优雅。改进:字符串强制
字符串表示是人类可读的,而 repr 有更多信息:
>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<Color.red: 1>
我发现这是对魔数(Magic Number)的改进,甚至可能比来自 namedtuple 的字符串更好。迭代(奇偶校验):
枚举也支持迭代(如namedtuple,但不是裸类):
>>> for color in Color:
print(color)
Color.red
Color.green
Color.blue
__members__
属性是枚举名称到其各自枚举对象的有序映射(类似于namedtuple 的_asdict()
函数)。>>> Color.__members__
mappingproxy(OrderedDict([('red', <Color.red: 1>), ('green', <Color.green: 2>),
('blue', <Color.blue: 3>)]))
由泡菜支持(奇偶校验)您可以序列化和反序列化枚举(以防有人担心):
>>> import pickle
>>> color.red is pickle.loads(pickle.dumps(color.red))
True
改进:别名这是一个很好的特性,裸类没有,而且很难判断别名是否存在于
namedtuple
中。 .class Color(Enum):
red = 1
green = 2
blue = 3
really_blue = 3
别名出现在规范名称之后,但它们都是相同的:>>> Color.blue is Color.really_blue
True
如果应该禁止别名以避免值冲突,请使用 enum.unique
装饰器(一个严格的主导特性)。严格占优:与
is
进行的比较枚举旨在使用
is
进行测试,这是对进程中单个对象身份的快速检查。>>> Color.red is Color.red
True
>>> Color.red is Color.blue
False
>>> Color.red is not Color.blue
True
相等性测试也有效,但使用 is
测试身份是最优的。与其他 Python 类不同的语义
枚举类与常规 Python 类型具有不同的语义。 Enum 的值是 Enum 的实例,并且是这些值在内存中的单例 - 实例化它们没有其他目的。
>>> Color.red is Color(1)
记住这一点很重要,也许这是一个缺点,但在这个维度上进行比较是将苹果与橙子进行比较。不假设枚举是有序的
虽然 Enum 类知道成员的创建顺序,但不假定枚举是有序的。这是一个特性,因为许多可以枚举的事物没有自然顺序,因此顺序是任意的。
但是,您可以给出枚举顺序(请参阅下一节)。
子类化
您不能对声明了成员的 Enum 进行子类化,但可以对未声明成员以共享行为的 Enum 进行子类化(请参阅 docs 中的 OrderedEnum 秘诀)。
这是一个特性——用成员子类化一个 Enum 没什么意义,但同样,比较是苹果和橘子。
我应该什么时候使用
enum.Enum
?这是 Python 中新的规范枚举。合作者会期望你的枚举表现得像这些枚举。
在您希望明确指定使用规范名称而不是任意数据的代码中具有规范的枚举数据源的任何地方使用它。
例如,如果在您的代码中您希望用户声明它不是
"Green"
, "green"
、2 或 "Greene"
,但是 Color.green
- 使用 enum.Enum 对象。它既明确又具体。documentation里面有很多例子和食谱.
我什么时候应该避开它们?
停止滚动你自己的或让人们猜测魔术数字和字符串。不要避开它们。拥抱他们。
但是,如果您的枚举成员因历史原因需要为整数,则可以使用
IntEnum
来自同一个模块,具有相同的行为,但也是一个整数,因为它继承了内置 int
子类化之前 Enum
.来自 IntEnum
的帮助:class IntEnum(builtins.int, Enum)
我们可以看到 IntEnum 值将作为 int
的实例进行测试。 .
关于Python,Enum 类型有什么用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37601644/