您的位置:  首页 » Python » enum模块支持枚举的详解(42)Python语言(必读进阶学习教程)(参考资料)

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

模块内容

该模块定义了可以用于定义名称和值的独特的套4枚举类:EnumIntEnumFlag,和 IntFlag。它还定义了一个装饰器unique()和一个辅助器auto

enum.Enum
用于创建枚举常量的基类。有关替代构造语法,请参阅功能API一节 。
enum.IntEnum
用于创建枚举常量的基类,它们也是子类int
enum.IntFlag
用于创建枚举常量的基类,可以使用按位运算符进行组合而不会丢失其IntFlag成员资格。 IntFlag成员也是子类int
enum.Flag
用于创建枚举常量的基类,可以使用按位运算组合而不会丢失其Flag成员资格。
enum.unique
枚举类装饰器,确保只有一个名称绑定到任何一个值。
enum.auto
实例将替换为Enum成员的适当值。

新的3.6版:FlagIntFlagauto

创建枚举

枚举是使用class语法创建的,这使它们易于读写。Functional API中描述了另一种创建方法 。要定义枚举,子类Enum如下:

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

 

注意

枚举成员值

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

注意

命名法

  • 该类Color枚举(或枚举
  • 的属性Color.REDColor.GREEN等等,都是 枚举成员(或枚举成员)和在功能上是常量。
  • 枚举成员具有名称(名称为 Color.REDis RED,值为Color.BLUEis 3等)

注意

即使我们使用class语法来创建枚举,但Enums不是普通的Python类。请参阅Enum如何与众不同?更多细节。

枚举成员具有人类可读的字符串表示形式:

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

 

……虽然他们repr有更多的信息:

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

 

枚举成员的类型是它所属的枚举:

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

 

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

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

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

 

如果要按名称访问枚举成员,请使用项目访问权限:

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

 

如果你有一个枚举成员并需要它namevalue

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

 

复制枚举成员和值

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

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

 

注意

尝试创建与已定义属性(另一个成员,方法等)同名的成员或尝试创建与成员同名的属性。

确保唯一的枚举值

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

@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

 

使用自动值

如果确切的值不重要,您可以使用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提供的方法,但它执行此操作的方式是实现细节,可能会更改。

迭代

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

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

 

比较

枚举成员按身份进行比较:

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

 

支持枚举值之间的有序比较。枚举成员不是整数(但请参见下面的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

 

允许的成员和枚举属性

上面的示例使用整数来表示枚举值。使用整数简短而方便(并且由Functional API默认提供),但不严格执行。在绝大多数用例中,人们并不关心枚举的实际价值。但是,如果值重要,枚举可以具有任意值。

枚举是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'

 

允许的规则如下:以单个下划线开头和结尾的名称由enum保留,不能使用; 枚举中定义将成为该列举的成员的所有其他属性,具有特殊的方法(例外__str__(), __add__()在列出的,等),描述符(方法也描述符),和变量名_ignore_

注意:如果您的枚举定义__new__()和/或__init__()然后给予枚举成员的任何值将被传递到这些方法中。有关示例,请参阅Planet

受限制的枚举子类

Enum类必须具有一个基本枚举类,最多一个具体数据类型,以及object根据需要具有多个基础的mixin类。这些基类的顺序是:

def EnumName([mix-in, ...,] [data-type,] base-enum):
    pass

 

此外,仅当枚举未定义任何成员时,才允许子类化枚举。所以这是禁止的:

>>>
>>> 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。)

酸洗

可以对枚举进行pickle和unpickled:

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

 

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

注意

使用pickle协议版本4,可以轻松地挑选嵌套在其他类中的枚举。

可以通过__reduce_ex__()在枚举类中定义来修改Enum成员的pickle / unpickled方式 。

功能

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是枚举的名称。

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

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

 

原因默认为1为起始号,而不是00False在布尔意义,但枚举成员都执行为True

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

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

 

警告

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

在某些情况下,新的泡菜协议4依赖于 __qualname__设置到泡菜能够找到该类的位置。例如,如果该类在全局范围内的类SomeData中可用:

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

 

完整的签名是:

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

新的Enum类将作为其名称记录。

名称:

Enum成员。这可以是空格或逗号分隔的字符串(除非另有说明,否则值将从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}
模块:

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

qualname:

在模块中可以找到新的Enum类。

类型:

键入以混合到新的Enum类。

开始:

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

在3.5版本中更改:启动加入参数。

派生枚举

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]

 

INTFLAG

下一变化Enum提供IntFlag,也是基于intIntFlag可以使用按位运算符(&,|,^,〜)组合成员的差异,结果仍然是 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>

 

IntFlag和之间的另一个重要区别Enum是,如果没有设置标志(值为0),它的布尔评估是False

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

 

因为IntFlag成员也是int它们的子类,所以它们可以与它们结合使用:

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

 

旗帜

最后一个变种是Flag。例如IntFlagFlag 可以使用按位运算符(&,|,^,〜)组合成员。IntFlag与之不同 ,它们不能与任何其他Flag枚举相结合,也不能与之相比int。虽然可以直接指定值,但建议将其auto用作值并Flag选择适当的值。

版本3.6中的新功能。

例如IntFlag,如果Flag成员组合导致没有设置标志,则布尔评估为False

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

 

单个标志的值应为2的幂(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

 

注意

对于大多数新代码,Enum并且Flag强烈建议,因为IntEnum并且IntFlag打破了枚举的一些语义承诺(通过与整数相比,因此通过对其他无关枚举的传递性)。 IntEnum 并且IntFlag只应在有Enum或 Flag没有的情况下使用; 例如,当整数常量被枚举替换时,或者与其他系统互操作时。

其他

虽然IntEnumenum模块的一部分,但它可以非常简单地独立实现:

class IntEnum(int, Enum):
    pass

 

这演示了如何定义类似的派生枚举; 例如StrEnum,混合str而不是int

一些规则:

  1. 当子类化时Enum,混合类型必须Enum在基本序列中出现在它自身之前 ,如上IntEnum 例所示。
  2. 虽然Enum可以包含任何类型的成员,但是一旦您混合使用其他类型,所有成员必须具有该类型的值,例如int上面的值。此限制不适用于仅添加方法且不指定其他数据类型(如int或)的混合 str
  3. 当另一数据类型被混合,该value属性是不一样的枚举构件本身,虽然它是等效,将比较相等。
  4. %样式格式: %s%r分别调用Enum类 __str__()__repr__(); 其他代码(例如 IntEnum的%i%h)将枚举成员视为其混合类型。
  5. 格式化字符串文字str.format()以及format()将采用混合式的__format__()。如果是或 希望使用Enum类,请使用!s!r格式代码。str()repr()

有趣的例子

虽然EnumIntEnumIntFlag,并Flag预计将覆盖大部分的使用情况,他们不能涵盖所有。以下是可以直接使用的一些不同类型的枚举的配方,或者作为创建自己的枚举的示例。

省略值

在许多用例中,人们并不关心枚举的实际值是什么。有几种方法可以定义这种类型的简单枚举:

  • 使用auto值的实例
  • 使用实例object作为值
  • 使用描述性字符串作为值
  • 使用元组作为值和自定义__new__()int值替换元组

使用这些方法中的任何一种都向用户表明这些值并不重要,并且还使用户可以添加,删除或重新排序成员,而无需重新编号其余成员。

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

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

 

使用auto

使用auto看起来像:

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

 

使用object

使用object看起来像:

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

 

使用描述性字符串

使用字符串作为值将如下所示:

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

 

使用自定义__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__()如果定义了该方法,则在创建Enum成员期间使用该方法; 然后将它替换为Enum __new__(),它在创建类之后用于查找现有成员。

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

 

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()可以使用装饰器。

星球

如果__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

 

TIMEPERIOD 

显示_ignore_正在使用的属性的示例:

>>>
>>> from datetime import timedelta
>>> class Period(timedelta, Enum):
...     "different lengths of time"
...     _ignore_ = 'Period i'
...     Period = vars()
...     for i in range(367):
...         Period['day_%d' % i] = i
...
>>> list(Period)[:2]
[<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]
>>> list(Period)[-2:]
[<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]

 

Enum与众不同?

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

枚举类

EnumMeta元类是负责提供 __contains__()__dir__()__iter__()和其他方法,使一个做事有Enum类于一个典型的类失败,如清单(彩色)some_enum_var的颜色。 EnumMeta是负责确保对最终各种其它方法Enum 类是正确的(例如__new__()__getnewargs__(), __str__()__repr__())。

枚举成员(又名实例)

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

更精细的点

支持的__dunder__名称

__members__OrderedDictmember_namemember 项目。它只在课堂上提供。

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

支持的_sunder_名称

  • _name_ – 会员姓名
  • _value_ – 会员价值; 可以设置/修改__new__
  • _missing_ – 未找到值时使用的查找函数; 可能会被覆盖
  • _ignore_– 作为a list()或a 的名称列表,str()不会转换为成员,并将从最终的类中删除
  • _order_ – 在Python 2/3代码中使用以确保成员顺序一致(类属性,在类创建期间删除)
  • _generate_next_value_-所用的功能性API,并通过 auto获得用于枚举成员一个适当的值; 可能会被覆盖

新的3.6版:_missing__order__generate_next_value_

版本3.7中的新功能: _ignore_

为了帮助保持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_属性是必需的,因为定义顺序在被记录之前就丢失了。

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已更改。

Enum类和成员的布尔值

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

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

 

Enum课程总是评估为True

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

 

结合成员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>

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注