Skip to main content

8.13. enum —支持枚举

3.4 新版功能.

源代码: Lib/enum.py


枚举是一组绑定到唯一的常量值的符号名(成员)。在枚举中,可以通过身份来比较成员,并且可以迭代枚举本身。

8.13.1. 模块内容

此模块定义了四个枚举类,可用于定义唯一的名称和值集合:EnumIntEnumIntFlags。它还定义了一个装饰器 unique() 和一个辅助器 auto

class enum.Enum

用于创建枚举常量的基类。有关其他构造语法,请参见 Functional API 部分。

class enum.IntEnum

创建枚举常量的基类,也是 int 的子类。

class enum.IntFlag

用于创建枚举常量的基类,可以使用按位运算符组合,而不会丢失其 IntFlag 成员资格。 IntFlag 成员也是 int 的亚类。

class enum.Flag

用于创建枚举常量的基类,可以使用按位操作组合,而不会丢失其 Flag 成员资格。

enum.unique()

枚举类装饰器,确保只有一个名称绑定到任何一个值。

class enum.auto

将枚举成员的实例替换为适当的值。

3.6 新版功能: FlagIntFlagauto

8.13.2. 创建枚举

枚举是使用 class 语法创建的,这使得它们易于读取和写入。在 Functional API 中描述了替代创建方法。要定义枚举,子类 Enum 如下:

>>> from enum import Enum
>>> class Color(Enum):
...     RED = 1
...     GREEN = 2
...     BLUE = 3
...

注解

枚举成员值

成员值可以是任何:intstr 等。如果确切的值不重要,您可以使用 auto 实例,并为您选择适当的值。如果将 auto 与其他值混合,必须小心。

注解

命名

  • Color 类是 enumeration (或 enum

  • 属性 Color.REDColor.GREEN 等是 枚举成员 (或 枚举成员),并且是功能上的常数。

  • 枚举成员有 namesvaluesColor.RED 的名称是 REDColor.BLUE 的值是 3 等)

注解

即使我们使用 class 语法创建枚举,枚举不是正常的Python类。有关详细信息,请参阅 How are Enums different?

枚举成员具有可读的字符串表示:

>>> print(Color.RED)
Color.RED

...而他们的 repr 有更多的信息:

>>> print(repr(Color.RED))
<Color.RED: 1>

枚举成员的 type 是它所属的枚举:

>>> type(Color.RED)
<enum 'Color'>
>>> isinstance(Color.GREEN, Color)
True
>>>

枚举成员还有一个仅包含其项目名称的属性:

>>> print(Color.RED.name)
RED

枚举按定义顺序支持迭代:

>>> class Shake(Enum):
...     VANILLA = 7
...     CHOCOLATE = 4
...     COOKIES = 9
...     MINT = 3
...
>>> for shake in Shake:
...     print(shake)
...
Shake.VANILLA
Shake.CHOCOLATE
Shake.COOKIES
Shake.MINT

枚举成员是可哈希的,因此它们可以在字典和集合中使用:

>>> apples = {}
>>> apples[Color.RED] = 'red delicious'
>>> apples[Color.GREEN] = 'granny smith'
>>> apples == {Color.RED: 'red delicious', Color.GREEN: 'granny smith'}
True

8.13.3. 对枚举成员及其属性的编程访问

有时,以编程方式访问枚举中的成员(即 Color.RED 不会这样做,因为在程序编写时不知道确切的颜色)是有用的。 Enum 允许这种访问:

>>> Color(1)
<Color.RED: 1>
>>> Color(3)
<Color.BLUE: 3>

如果要通过 name 访问枚举成员,请使用项目访问:

>>> Color['RED']
<Color.RED: 1>
>>> Color['GREEN']
<Color.GREEN: 2>

如果你有一个枚举成员,需要它的 namevalue:

>>> member = Color.RED
>>> member.name
'RED'
>>> member.value
1

8.13.4. 复制枚举成员和值

具有相同名称的两个枚举成员无效:

>>> class Shape(Enum):
...     SQUARE = 2
...     SQUARE = 3
...
Traceback (most recent call last):
...
TypeError: Attempted to reuse key: 'SQUARE'

但是,两个枚举成员允许具有相同的值。给定两个成员A和B具有相同的值(并且A首先定义),B是A的别名。A和B的值的值的查找将返回A. B的按名称查找也将返回A:

>>> class Shape(Enum):
...     SQUARE = 2
...     DIAMOND = 1
...     CIRCLE = 3
...     ALIAS_FOR_SQUARE = 2
...
>>> Shape.SQUARE
<Shape.SQUARE: 2>
>>> Shape.ALIAS_FOR_SQUARE
<Shape.SQUARE: 2>
>>> Shape(2)
<Shape.SQUARE: 2>

注解

尝试创建与已定义的属性(另一个成员,方法等)具有相同名称的成员或尝试创建与成员具有相同名称的属性是不允许的。

8.13.5. 确保唯一的枚举值

默认情况下,枚举允许多个名称作为同一值的别名。当不需要此行为时,可以使用以下装饰器来确保每个值在枚举中仅使用一次:

@enum.unique

class 装饰器专门用于枚举。它搜索枚举的 __members__ 收集它找到的任何别名;如果发现 ValueError 与细节提出:

>>> from enum import Enum, unique
>>> @unique
... class Mistake(Enum):
...     ONE = 1
...     TWO = 2
...     THREE = 3
...     FOUR = 3
...
Traceback (most recent call last):
...
ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE

8.13.6. 使用自动值

如果确切的值不重要,您可以使用 auto:

>>> from enum import Enum, auto
>>> class Color(Enum):
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()
...
>>> list(Color)
[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

这些值由 _generate_next_value_() 选择,可以覆盖:

>>> 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'>]

注解

默认 _generate_next_value_() 方法的目标是提供下一个 int 与提供的最后一个 int,但是它是一个实现细节,可能会改变。

8.13.7. 迭代

迭代枚举的成员不提供别名:

>>> list(Shape)
[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]

特殊属性 __members__ 是将名称映射到成员的有序字典。它包括枚举中定义的所有名称,包括别名:

>>> for name, member in Shape.__members__.items():
...     name, member
...
('SQUARE', <Shape.SQUARE: 2>)
('DIAMOND', <Shape.DIAMOND: 1>)
('CIRCLE', <Shape.CIRCLE: 3>)
('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)

__members__ 属性可用于详细编程访问枚举成员。例如,查找所有别名:

>>> [name for name, member in Shape.__members__.items() if member.name != name]
['ALIAS_FOR_SQUARE']

8.13.8. 比较

枚举成员通过标识进行比较:

>>> Color.RED is Color.RED
True
>>> Color.RED is Color.BLUE
False
>>> Color.RED is not Color.BLUE
True

枚举值之间的有序比较是 not 支持的。枚举成员不是整数(但参见下面的 IntEnum):

>>> Color.RED < Color.BLUE
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'Color' and 'Color'

平等比较被定义:

>>> Color.BLUE == Color.RED
False
>>> Color.BLUE != Color.RED
True
>>> Color.BLUE == Color.BLUE
True

与非枚举值的比较将总是比较不相等(再次,IntEnum 被明确地设计为具有不同的行为,见下文):

>>> Color.BLUE == 2
False

8.13.9. 允许枚举的成员和属性

上面的示例使用整数作为枚举值。使用整数是简短和方便(默认情况下由 Functional API 提供),但不严格执行。在绝大多数用例中,人们不关心枚举的实际值。但是如果值 is 很重要,枚举可以有任意值。

枚举是Python类,可以有通常的方法和特殊方法。如果我们有这个枚举:

>>> class Mood(Enum):
...     FUNKY = 1
...     HAPPY = 3
...
...     def describe(self):
...         # self is the member here
...         return self.name, self.value
...
...     def __str__(self):
...         return 'my custom str! {0}'.format(self.value)
...
...     @classmethod
...     def favorite_mood(cls):
...         # cls here is the enumeration
...         return cls.HAPPY
...

然后:

>>> Mood.favorite_mood()
<Mood.HAPPY: 3>
>>> Mood.HAPPY.describe()
('HAPPY', 3)
>>> str(Mood.FUNKY)
'my custom str! 1'

允许的规则如下:以单个下划线开始和结束的名称由枚举保留,不能使用;枚举中定义的所有其他属性将成为此枚举的成员,但特殊方法(__str__()__add__() 等)和描述符(方法也是描述符)除外。

注意:如果你的枚举定义 __new__() 和/或 __init__(),那么给枚举成员的任何值都将被传递到这些方法中。参见 Planet 的例子。

8.13.10. 枚举的限制子类化

只有枚举没有定义任何成员时,才允许子类化枚举。所以这是禁止的:

>>> class MoreColor(Color):
...     PINK = 17
...
Traceback (most recent call last):
...
TypeError: Cannot extend enumerations

但这是允许的:

>>> class Foo(Enum):
...     def some_behavior(self):
...         pass
...
>>> class Bar(Foo):
...     HAPPY = 1
...     SAD = 2
...

允许定义成员的枚举的子类化将导致违反类型和实例的一些重要不变量。另一方面,允许在一组枚举之间共享一些常见行为是有意义的。 (见 OrderedEnum 的例子。)

8.13.11. 酸洗

枚举可以进行pickle和unpickled:

>>> from test.test_enum import Fruit
>>> from pickle import dumps, loads
>>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
True

酸洗的通常限制适用:pickleable枚举必须在模块的顶层定义,因为unpickling要求它们可从该模块导入。

注解

使用pickle协议版本4,可以容易地腌排嵌套在其他类中的枚举。

可以通过在枚举类中定义 __reduce_ex__() 来修改如何对Enum成员进行pickle/unpickled。

8.13.12. 功能API

Enum 类是可调用的,提供以下功能API:

>>> Animal = Enum('Animal', 'ANT BEE CAT DOG')
>>> Animal
<enum 'Animal'>
>>> Animal.ANT
<Animal.ANT: 1>
>>> Animal.ANT.value
1
>>> list(Animal)
[<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]

这个API的语义类似于 namedtuple。调用 Enum 的第一个参数是枚举的名称。

第二个参数是枚举成员名称的 source。它可以是空格分隔的名称字符串,名称序列,具有键/值对的2元组序列,或名称到值的映射(例如字典)。最后两个选项允许将任意值分配给枚举;其他自动分配从1开始递增的整数(使用 start 参数指定不同的起始值)。返回从 Enum 派生的新类。换句话说,上面对 Animal 的分配等同于:

>>> class Animal(Enum):
...     ANT = 1
...     BEE = 2
...     CAT = 3
...     DOG = 4
...

默认为 1 作为起始号而不是 0 的原因是 0 是布尔意义上的 False,但枚举成员都评估为 True

使用功能API创建的pickle枚举可能很棘手,因为框架堆栈实现细节用于尝试并找出枚举创建在哪个模块(例如,如果在单独的模块中使用效用函数,它将失败,也可能无法工作在IronPython或Jython)。解决方案是明确指定模块名称如下:

>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)

警告

如果没有提供 module,并且Enum不能确定它是什么,新的Enum成员将不会取消取消;为了使错误更接近源,pickling将被禁用。

在某些情况下,新的pickle协议4还依赖于 __qualname__ 被设置为pickle将能够找到该类的位置。例如,如果类在全局作用域中的SomeData类中可用:

>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')

完整的签名是:

Enum(value='NewEnumName', names=<...>, *, module='...', qualname='...', type=<mixed-in class>, start=1)
value:

新的Enum类将记录为它的名称。

names:

枚举成员。这可以是空格或逗号分隔的字符串(除非另有说明,否则值将从1开始):

'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'

或名称的迭代器:

['RED', 'GREEN', 'BLUE']

或(名称,值)对的迭代器:

[('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]

或映射:

{'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}
module:

模块的名称,其中可以找到新的Enum类。

qualname:

其中在module中可以找到新的Enum类。

type:

类型混合到新的Enum类中。

start:

如果只传入名称,则开始计数的数字。

在 3.5 版更改: 添加了 start 参数。

8.13.13. 派生枚举

8.13.13.1. IntEnum

所提供的 Enum 的第一变体也是 int 的子类。 IntEnum 的成员可以与整数比较;通过扩展,不同类型的整数枚举也可以彼此比较:

>>> from enum import IntEnum
>>> class Shape(IntEnum):
...     CIRCLE = 1
...     SQUARE = 2
...
>>> class Request(IntEnum):
...     POST = 1
...     GET = 2
...
>>> Shape == 1
False
>>> Shape.CIRCLE == 1
True
>>> Shape.CIRCLE == Request.POST
True

然而,它们仍然不能与标准 Enum 枚举进行比较:

>>> class Shape(IntEnum):
...     CIRCLE = 1
...     SQUARE = 2
...
>>> class Color(Enum):
...     RED = 1
...     GREEN = 2
...
>>> Shape.CIRCLE == Color.RED
False

IntEnum 值的行为像整数在你想要的其他方式:

>>> int(Shape.CIRCLE)
1
>>> ['a', 'b', 'c'][Shape.CIRCLE]
'b'
>>> [i for i in range(Shape.SQUARE)]
[0, 1]

8.13.13.2. IntFlag

提供的 Enum 的下一个变体 IntFlag 也基于 int。区别是 IntFlag 成员可以使用按位运算符(&,|,^,~)组合,结果仍然是 IntFlag 成员。然而,顾名思义,IntFlag 成员也子类化 int 并且可以在使用 int 的任何地方使用。除了逐位操作之外的 IntFlag 成员上的任何操作将丢失 IntFlag 成员资格。

3.6 新版功能.

样本 IntFlag 类:

>>> from enum import IntFlag
>>> class Perm(IntFlag):
...     R = 4
...     W = 2
...     X = 1
...
>>> Perm.R | Perm.W
<Perm.R|W: 6>
>>> Perm.R + Perm.W
6
>>> RW = Perm.R | Perm.W
>>> Perm.R in RW
True

也可以命名组合:

>>> class Perm(IntFlag):
...     R = 4
...     W = 2
...     X = 1
...     RWX = 7
>>> Perm.RWX
<Perm.RWX: 7>
>>> ~Perm.RWX
<Perm.-8: -8>

IntFlagEnum 之间的另一个重要区别是,如果没有设置标志(值为0),则其布尔值为 False:

>>> Perm.R & Perm.X
<Perm.0: 0>
>>> bool(Perm.R & Perm.X)
False

因为 IntFlag 成员也是 int 的子类,它们可以与它们组合:

>>> Perm.X | 8
<Perm.8|X: 9>

8.13.13.3. 旗

最后一个变化是 Flag。像 IntFlag 一样,Flag 成员可以使用按位运算符(&,|,^,~)组合。与 IntFlag 不同,它们不能与任何其他 Flag 枚举组合,也不能与 int 进行比较。尽管可以直接指定值,但推荐使用 auto 作为值,并让 Flag 选择一个适当的值。

3.6 新版功能.

IntFlag 一样,如果 Flag 成员的组合导致没有设置标志,则布尔值评估是 False:

>>> from enum import Flag
>>> class Color(Flag):
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()
...
>>> Color.RED & Color.GREEN
<Color.0: 0>
>>> bool(Color.RED & Color.GREEN)
False

单独的标志应该有两个幂的值(1,2,4,8,...),而标志的组合不会:

>>> class Color(Flag):
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()
...     WHITE = RED | BLUE | GREEN
...
>>> Color.WHITE
<Color.WHITE: 7>

给“无标志集”条件命名不会改变其布尔值:

>>> class Color(Flag):
...     BLACK = 0
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()
...
>>> Color.BLACK
<Color.BLACK: 0>
>>> bool(Color.BLACK)
False

注解

对于大多数新代码,强烈建议使用 EnumFlag,因为 IntEnumIntFlag 会破坏枚举的某些语义承诺(通过与整数相比较,并因此与其他不相关的枚举的传递性)。 IntEnumIntFlag 只应在 EnumFlag 不使用的情况下使用;例如,当整数常量被枚举替代,或者用于与其他系统的互操作性。

8.13.13.4. 其他

虽然 IntEnumenum 模块的一部分,但是独立实现将非常简单:

class IntEnum(int, Enum):
    pass

这说明如何定义类似的派生枚举;例如混合在 str 而不是 int 中的 StrEnum

一些规则:

  1. 当子类化 Enum 时,混合类型必须出现在 Enum 本身之前的碱基序列中,如上述 IntEnum 示例中所示。

  2. 虽然 Enum 可以有任何类型的成员,一旦你混合一个附加类型,所有成员必须有该类型的值,例如。 int。此限制不适用于仅添加方法且不指定其他数据类型(例如 intstr)的混合。

  3. 当混合其他数据类型时,value 属性是 不一样 作为枚举成员本身,虽然它是等价的,并将比较相等。

  4. %样式格式化:%s%r 分别调用 Enum 类的 __str__()__repr__();其他代码(例如 %i 或IntEnum的 %h)将枚举成员视为其混合类型。

  5. 格式化字符串文字str.format()format() 将使用混合型 __format__()。如果需要 Enum 类的 str()repr(),请使用 !s!r 格式代码。

8.13.14. 有趣的例子

虽然 EnumIntEnumIntFlagFlag 预计覆盖大多数用例,但它们不能涵盖所有这些。这里是一些不同类型的枚举的配方,可以直接使用,或作为创建自己的例子。

8.13.14.1. 省略值

在许多使用情况下,人们不关心枚举的实际值。有几种方法来定义这种类型的简单枚举:

  • 使用 auto 的实例作为值

  • 使用 object 的实例作为值

  • 使用描述性字符串作为值

  • 使用元组作为值,并使用自定义 __new__()int 值替换元组

使用任何这些方法向用户表明这些值不重要,并且还使得能够添加,删除或重新排序成员,而不必对剩余成员重新编号。

无论您选择哪种方法,都应提供一个也隐藏(不重要)值的 repr():

>>> class NoValue(Enum):
...     def __repr__(self):
...         return '<%s.%s>' % (self.__class__.__name__, self.name)
...

8.13.14.1.1. 使用 auto

使用 object 将看起来像:

>>> class Color(NoValue):
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()
...
>>> Color.GREEN
<Color.GREEN>

8.13.14.1.2. 使用 object

使用 object 将看起来像:

>>> class Color(NoValue):
...     RED = object()
...     GREEN = object()
...     BLUE = object()
...
>>> Color.GREEN
<Color.GREEN>

8.13.14.1.3. 使用描述性字符串

使用字符串作为值看起来像:

>>> class Color(NoValue):
...     RED = 'stop'
...     GREEN = 'go'
...     BLUE = 'too fast!'
...
>>> Color.GREEN
<Color.GREEN>
>>> Color.GREEN.value
'go'

8.13.14.1.4. 使用自定义 __new__()

使用自动编号 __new__() 将看起来像:

>>> class AutoNumber(NoValue):
...     def __new__(cls):
...         value = len(cls.__members__) + 1
...         obj = object.__new__(cls)
...         obj._value_ = value
...         return obj
...
>>> class Color(AutoNumber):
...     RED = ()
...     GREEN = ()
...     BLUE = ()
...
>>> Color.GREEN
<Color.GREEN>
>>> Color.GREEN.value
2

注解

__new__() 方法(如果定义的话)在创建枚举成员期间使用;它随后被替换为枚举的 __new__(),它在类创建后用于查找现有成员。

8.13.14.2. OrderedEnum

不是基于 IntEnum 的有序枚举,因此保持正常的 Enum 不变量(例如不能与其他枚举相比较):

>>> class OrderedEnum(Enum):
...     def __ge__(self, other):
...         if self.__class__ is other.__class__:
...             return self.value >= other.value
...         return NotImplemented
...     def __gt__(self, other):
...         if self.__class__ is other.__class__:
...             return self.value > other.value
...         return NotImplemented
...     def __le__(self, other):
...         if self.__class__ is other.__class__:
...             return self.value <= other.value
...         return NotImplemented
...     def __lt__(self, other):
...         if self.__class__ is other.__class__:
...             return self.value < other.value
...         return NotImplemented
...
>>> class Grade(OrderedEnum):
...     A = 5
...     B = 4
...     C = 3
...     D = 2
...     F = 1
...
>>> Grade.C < Grade.A
True

8.13.14.3. DuplicateFreeEnum

如果找到重复的成员名称而不是创建别名,则会引发错误:

>>> class DuplicateFreeEnum(Enum):
...     def __init__(self, *args):
...         cls = self.__class__
...         if any(self.value == e.value for e in cls):
...             a = self.name
...             e = cls(self.value).name
...             raise ValueError(
...                 "aliases not allowed in DuplicateFreeEnum:  %r --> %r"
...                 % (a, e))
...
>>> class Color(DuplicateFreeEnum):
...     RED = 1
...     GREEN = 2
...     BLUE = 3
...     GRENE = 2
...
Traceback (most recent call last):
...
ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'

注解

这是一个有用的示例,用于子类化Enum以添加或更改其他行为以及禁止别名。如果唯一所需的更改是禁止别名,则可以改为使用 unique() 装饰器。

8.13.14.4. 行星

如果定义了 __new__()__init__(),则枚举成员的值将传递到这些方法:

>>> class Planet(Enum):
...     MERCURY = (3.303e+23, 2.4397e6)
...     VENUS   = (4.869e+24, 6.0518e6)
...     EARTH   = (5.976e+24, 6.37814e6)
...     MARS    = (6.421e+23, 3.3972e6)
...     JUPITER = (1.9e+27,   7.1492e7)
...     SATURN  = (5.688e+26, 6.0268e7)
...     URANUS  = (8.686e+25, 2.5559e7)
...     NEPTUNE = (1.024e+26, 2.4746e7)
...     def __init__(self, mass, radius):
...         self.mass = mass       # in kilograms
...         self.radius = radius   # in meters
...     @property
...     def surface_gravity(self):
...         # universal gravitational constant  (m3 kg-1 s-2)
...         G = 6.67300E-11
...         return G * self.mass / (self.radius * self.radius)
...
>>> Planet.EARTH.value
(5.976e+24, 6378140.0)
>>> Planet.EARTH.surface_gravity
9.802652743337129

8.13.15. 如何不同?

枚举有一个自定义元类,它影响派生的Enum类及其实例(成员)的许多方面。

8.13.15.1. 枚举类

EnumMeta 元类负责提供 __contains__()__dir__()__iter__() 和其他允许使用在典型类(例如 list(Color)some_var in Color)上失败的 Enum 类做事情的方法。 EnumMeta 负责确保最终 Enum 类上的各种其他方法是正确的(例如 __new__()__getnewargs__()__str__()__repr__())。

8.13.15.2. 枚举成员(又名实例)

Enum成员最有趣的是它们是单例。 EnumMeta 在创建 Enum 类本身时创建它们,然后放置自定义 __new__(),以确保不会通过仅返回现有成员实例来实例化新的 __new__()

8.13.15.3. 美分

8.13.15.3.1. 支持的 __dunder__ 名称

__members__member_name:member 项的 OrderedDict。它只在类上可用。

__new__() (如果指定)必须创建并返回枚举成员;它也是一个很好的主意,适当地设置成员的 _value_。一旦所有成员被创建,它就不再使用。

8.13.15.3.2. 支持的 _sunder_ 名称

  • _name_ - 成员的名称

  • _value_ - 成员的价值;可以在 __new__ 中设置/修改

  • _missing_ - 当找不到值时使用的查找函数;可以被覆盖

  • _order_ - 用于Python 2/3代码,以确保成员顺序一致(类属性,在类创建期间删除)

  • _generate_next_value_ - 由 Functional APIauto 使用以为枚举成员获取适当的值;可以被覆盖

3.6 新版功能: _missing__order__generate_next_value_

为了帮助保持Python 2 / Python 3代码同步,可以提供 _order_ 属性。它将根据枚举的实际顺序进行检查,并且如果两者不匹配则产生错误:

>>> class Color(Enum):
...     _order_ = 'RED GREEN BLUE'
...     RED = 1
...     BLUE = 3
...     GREEN = 2
...
Traceback (most recent call last):
...
TypeError: member order does not match _order_

注解

在Python 2代码中,_order_ 属性是必要的,因为定义顺序在可以被记录之前就丢失了。

8.13.15.3.3. Enum 成员类型

Enum 成员是其 Enum 类的实例,通常作为 EnumClass.member 访问。在某些情况下,他们也可以作为 EnumClass.member.member 访问,但是你不应该这样做,因为查找可能失败,或者更糟的是,返回除了你正在寻找的 Enum 成员之外的东西(这是另一个很好的理由为成员使用大写名称):

>>> class FieldTypes(Enum):
...     name = 0
...     value = 1
...     size = 2
...
>>> FieldTypes.value.size
<FieldTypes.size: 2>
>>> FieldTypes.size.value
2

在 3.5 版更改.

8.13.15.3.4. Enum 类和成员的布尔值

根据混合型规则评价与非 Enum 类型(例如 intstr 等)混合的 Enum 成员;否则,所有成员评价为 True。要使自己的Enum的布尔值求值取决于成员的值,请在类中添加以下内容:

def __bool__(self):
    return bool(self.value)

Enum 类总是评估为 True

8.13.15.3.5. Enum 类与方法

如果你给你的 Enum 子类额外的方法,如上面的 Planet 类,这些方法将显示在成员的 dir() 中,但不是类的:

>>> dir(Planet)
['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__members__', '__module__']
>>> dir(Planet.EARTH)
['__class__', '__doc__', '__module__', 'name', 'surface_gravity', 'value']

8.13.15.3.6. 结合 Flag 成员

如果未命名Flag成员的组合,则 repr() 将包括所有命名标志和在值中的所有命名的标志组合:

>>> class Color(Flag):
...     RED = auto()
...     GREEN = auto()
...     BLUE = auto()
...     MAGENTA = RED | BLUE
...     YELLOW = RED | GREEN
...     CYAN = GREEN | BLUE
...
>>> Color(3)  # named combination
<Color.YELLOW: 3>
>>> Color(7)      # not named combination
<Color.CYAN|MAGENTA|BLUE|YELLOW|GREEN|RED: 7>