enum
---支持枚举¶
3.4 新版功能.
源代码: Lib/enum.py
枚举是一组绑定到唯一常量值的符号名(成员)。在枚举中,可以按标识比较成员,并且可以迭代枚举本身。
注解
枚举成员的情况
因为枚举用于表示常量,所以我们建议对枚举成员使用大写字母的名称,并且将在我们的示例中使用这种样式。
模块内容¶
此模块定义四个枚举类,可用于定义唯一的名称和值集: Enum
, IntEnum
, Flag
和 IntFlag
. 它还定义了一个装饰器, unique()
和一个助手, auto
.
- class enum.Enum¶
用于创建枚举常量的基类。参见第节 Functional API 用于替代结构语法。
- enum.unique()
确保只有一个名称绑定到任何一个值的枚举类修饰符。
3.6 新版功能: Flag
, IntFlag
, auto
3.10 新版功能: StrEnum
创建枚举¶
枚举是使用 class
语法,使它们易于读写。中描述了另一种创建方法。 Functional API . 要定义枚举,子类 Enum
如下:
>>> from enum import Enum
>>> class Color(Enum):
... RED = 1
... GREEN = 2
... BLUE = 3
...
注解
命名法
类
Color
是一个 枚举 (或) enum )属性
Color.RED
,Color.GREEN
等等,都是 枚举成员 (或) 枚举成员 )和在功能上是常量。枚举成员具有 姓名 和 价值观 (名字)
Color.RED
是RED
的价值Color.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
枚举成员是可hash的,因此可以在字典和集合中使用:
>>> 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>
如果要通过以下方式访问枚举成员: name ,使用项访问::
>>> Color['RED']
<Color.RED: 1>
>>> Color['GREEN']
<Color.GREEN: 2>
如果您有一个枚举成员并且需要它 name
或 value
::
>>> member = Color.RED
>>> member.name
'RED'
>>> member.value
1
复制枚举成员和值¶
具有两个同名的枚举成员无效::
>>> class Shape(Enum):
... SQUARE = 2
... SQUARE = 3
...
Traceback (most recent call last):
...
TypeError: 'SQUARE' already defined as: 2
但是,允许两个枚举成员具有相同的值。如果两个成员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¶
A 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_()
方法必须在任何成员之前定义。
迭代¶
迭代枚举的成员不提供别名::
>>> 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
枚举值之间的有序比较是 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
允许枚举的成员和属性¶
上面的示例使用整数作为枚举值。使用整数既短又方便(默认情况下由 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__()
等)、描述符(方法也是描述符)和中列出的变量名 _ignore_
.
注意:如果枚举定义了 __new__()
和/或 __init__()
然后,给枚举成员的任何值都将传递到这些方法中。见 Planet 举个例子。
受限枚举子类化¶
一个新的 Enum
类必须有一个基本枚举类,最多一个具体的数据类型,以及尽可能多的 object
-根据需要基于mixin类。这些基类的顺序是:
class EnumName([mix-in, ...,] [data-type,] base-enum):
pass
此外,只有枚举没有定义任何成员时,才允许对枚举进行子类化。所以这是禁止的:
>>> class MoreColor(Color):
... PINK = 17
...
Traceback (most recent call last):
...
TypeError: MoreColor: cannot extend enumeration 'Color'
但这是允许的:
>>> class Foo(Enum):
... def some_behavior(self):
... pass
...
>>> class Bar(Foo):
... HAPPY = 1
... SAD = 2
...
允许对定义成员的枚举进行子类化会导致违反一些重要的类型和实例不变量。另一方面,允许在一组枚举之间共享一些常见行为是有意义的。(见 OrderedEnum 例如。)
Pickling¶
可以对枚举进行pickle和unpickle::
>>> from test.test_enum import Fruit
>>> from pickle import dumps, loads
>>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
True
pickling的常见限制适用:可拾取枚举必须在模块的顶层定义,因为取消拾取要求它们可以从该模块导入。
注解
使用pickle协议版本4,可以轻松地pickle嵌套在其他类中的枚举。
可以通过定义 __reduce_ex__()
在枚举类中。
功能性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创建的picking枚举可能很棘手,因为框架堆栈实现细节用于尝试并确定枚举是在哪个模块中创建的(例如,如果在单独的模块中使用实用程序函数,它将失败,也可能无法在Ironpython或Jython上工作)。解决方案是显式指定模块名称,如下所示:
>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)
警告
如果 module
未提供,并且枚举无法确定它是什么,新的枚举成员将不会取消拾取;为了使错误更接近源,将禁用pirach。
在某些情况下,新的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)
- 价值
新枚举类将记录什么作为其名称。
- 姓名
枚举成员。这可以是空白或逗号分隔的字符串(除非另有规定,否则值将从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}
- 模块
可以找到新枚举类的模块的名称。
- 质量名称
在模块中可以找到新的枚举类。
- 类型
键入以混合到新枚举类中。
- 开始
如果只传入名称,则开始计数的数字。
在 3.5 版更改: 这个 开始 已添加参数。
派生枚举¶
IntEnum¶
第一个变化 Enum
它也是 int
. AN成员 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]
StrEnum¶
第二个变体 Enum
它也是 str
. a的成员 StrEnum
可以与字符串进行比较;通过扩展,不同类型的字符串枚举也可以相互比较。 StrEnum
存在以帮助避免获取错误成员的问题:
>>> from enum import StrEnum
>>> class Directions(StrEnum):
... NORTH = 'north', # notice the trailing comma
... SOUTH = 'south'
之前 StrEnum
, Directions.NORTH
会是 tuple
('north',)
.
注解
与其他枚举不同, str(StrEnum.member)
将返回成员的值而不是通常的 "EnumClass.member"
.
3.10 新版功能.
IntFlag¶
的下一个变种 Enum
只要, IntFlag
,也是基于 int
。不同之处在于 IntFlag
可以使用按位运算符(&、|、^、~)组合成员,并且结果仍然是 IntFlag
如果可能的话,请议员发言。然而,顾名思义, IntFlag
成员也是子类别 int
并且可以在任何地方使用 int
是使用的。
3.6 新版功能.
在 3.10 版更改.
样品 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: 0>
>>> Perm(7)
<Perm.RWX: 7>
注解
命名组合被视为别名。别名在迭代期间不会显示,但可以从按值查找中返回。
在 3.10 版更改.
另一个重要区别是 IntFlag
和 Enum
如果没有设置任何标志(值为0),则其布尔值为 False
::
>>> Perm.R & Perm.X
<Perm: 0>
>>> bool(Perm.R & Perm.X)
False
因为 IntFlag
成员也是 int
它们可以与它们合并(但可能会失败 IntFlag
成员::
>>> Perm.X | 4
<Perm.R|X: 5>
>>> Perm.X | 8
9
IntFlag
成员也可以迭代:
>>> list(RW)
[<Perm.R: 4>, <Perm.W: 2>]
3.10 新版功能.
旗¶
最后一个变化是 Flag
. 类似于 IntFlag
, Flag
可以使用位运算符(&、、^、~)组合成员。不像 IntFlag
,它们不能与任何其他项组合,也不能与任何其他项进行比较。 Flag
枚举,nor 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>
>>> 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>
为“no flags set”条件命名不会更改其布尔值:
>>> class Color(Flag):
... BLACK = 0
... RED = auto()
... BLUE = auto()
... GREEN = auto()
...
>>> Color.BLACK
<Color.BLACK: 0>
>>> bool(Color.BLACK)
False
Flag
成员也可以迭代:
>>> purple = Color.RED | Color.BLUE
>>> list(purple)
[<Color.RED: 1>, <Color.BLUE: 2>]
3.10 新版功能.
其他¶
同时 IntEnum
是 enum
模块,独立实现非常简单:
class IntEnum(int, Enum):
pass
这演示了如何定义类似的派生枚举;例如 StrEnum
混入 str
而不是 int
.
一些规则:
同时
Enum
可以有任何类型的成员,一旦混合到其他类型中,所有成员都必须具有该类型的值,例如。int
上面。此限制不适用于只添加方法而不指定其他类型的混合插件。当混合了另一种数据类型时,
value
属性是 不一样 作为枚举成员本身,尽管它是等效的,并且将比较相等。%-样式格式: %s and %r call the
Enum
class's__str__()
__repr__()
分别;其他代码(如 %i 或 %h 对于intenum)将枚举成员视为其混合类型。Formatted string literals ,
str.format()
和format()
将使用混合类型的__format__()
除非__str__()
或__format__()
在子类中重写,在这种情况下,重写的方法或Enum
将使用方法。使用!S和!R格式代码强制使用Enum
班的__str__()
和__repr__()
方法。
何时使用 __new__()
VS __init__()
¶
__new__()
必须在要自定义 Enum
成员。任何其他修改都可以 __new__()
或 __init__()
用 __init__()
优先考虑。
例如,如果要将多个项传递给构造函数,但只希望其中一个项是值::
>>> class Coordinate(bytes, Enum):
... """
... Coordinate with binary codes that can be indexed by the int code.
... """
... def __new__(cls, value, label, unit):
... obj = bytes.__new__(cls, [value])
... obj._value_ = value
... obj.label = label
... obj.unit = unit
... return obj
... PX = (0, 'P.X', 'km')
... PY = (1, 'P.Y', 'km')
... VX = (2, 'V.X', 'km/s')
... VY = (3, 'V.Y', 'km/s')
...
>>> print(Coordinate['PY'])
Coordinate.PY
>>> print(Coordinate(3))
Coordinate.VY
有趣的例子¶
同时 Enum
, IntEnum
, IntFlag
和 Flag
预计将覆盖大多数用例,它们不能覆盖所有用例。以下是一些不同类型的枚举的方法,可以直接使用,也可以作为创建自己的枚举的示例。
省略值¶
在许多用例中,人们不关心枚举的实际值是什么。有几种方法可以定义这种类型的简单枚举:
使用这些方法中的任何一种都意味着这些值并不重要,而且还允许用户添加、删除或重新排序成员,而无需对其余成员重新编号。
无论您选择哪种方法,都应提供 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
为了达到一个更普遍的目的 AutoNumber
,添加 *args
签字人:
>>> class AutoNumber(NoValue):
... def __new__(cls, *args): # this is the only change from above
... value = len(cls.__members__) + 1
... obj = object.__new__(cls)
... obj._value_ = value
... return obj
...
当你继承 AutoNumber
你可以自己写 __init__
要处理任何额外的参数:
>>> class Swatch(AutoNumber):
... def __init__(self, pantone='unknown'):
... self.pantone = pantone
... AUBURN = '3497'
... SEA_GREEN = '1246'
... BLEACHED_CORAL = () # New color, no Pantone code yet!
...
>>> Swatch.SEA_GREEN
<Swatch.SEA_GREEN>
>>> Swatch.SEA_GREEN.pantone
'1246'
>>> Swatch.BLEACHED_CORAL.pantone
'unknown'
注解
这个 __new__()
方法(如果已定义)在创建枚举成员期间使用;然后用枚举的 __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'
注解
这是一个很有用的例子,可以通过子类化枚举来添加或更改其他行为,以及禁止别名。如果唯一需要的更改是不允许使用别名,则 unique()
可以改用decorator。
行星¶
如果 __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)>]
枚举有什么不同?¶
枚举有一个自定义元类,它影响派生枚举类及其实例(成员)的许多方面。
枚举类¶
这个 EnumMeta
元类负责提供 __contains__()
, __dir__()
, __iter__()
以及其他可以让人用 Enum
在典型类上失败的类,例如 list(Color) or some_enum_var in Color. EnumMeta
is responsible for ensuring that various other methods on the final Enum
class are correct (such as _ _new__()
, __getnewargs__()
, __str__()
和 __repr__()
)
枚举成员(aka实例)¶
枚举成员最有趣的一点是它们是单例的。 EnumMeta
在创建 Enum
类本身,然后将 __new__()
通过只返回现有的成员实例来确保没有新的实例被实例化。
Finer点¶
支持 __dunder__
姓名¶
__members__
是的只读顺序映射 member_name
:member
项目。它只在课堂上提供。
__new__()
如果指定,则必须创建并返回枚举成员;设置成员的 _value_
适当地。创建所有成员后,将不再使用它。
支持 _sunder_
姓名¶
_name_
--成员的姓名_value_
-- value of the member; can be set / modified in__new__
_missing_
--找不到值时使用的查找函数;可以重写_order_
--在python 2/3代码中使用,以确保成员顺序一致(class属性,在类创建期间移除)_generate_next_value_
--由 Functional 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_:
['RED', 'BLUE', 'GREEN']
['RED', 'GREEN', 'BLUE']
注解
在python 2中,对 _order_
属性是必需的,因为定义顺序在记录之前已丢失。
_Private__names¶
专用名称不会转换为枚举成员,但会保留普通属性。
在 3.10 版更改.
Enum
成员类型¶
Enum
成员是其 Enum
类,并且通常作为 EnumClass.member
。在Python版本中 3.5
至 3.9
您可以从其他成员访问成员--不鼓励这种做法,并且在 3.10
Enum
又回到了不允许它的状态::
>>> class FieldTypes(Enum):
... name = 0
... value = 1
... size = 2
...
>>> FieldTypes.value.size
Traceback (most recent call last):
...
AttributeError: FieldTypes: no attribute 'size'
在 3.5 版更改.
在 3.10 版更改.
创建与其他数据类型混合的成员¶
当子类化其他数据类型时,例如 int
或 str
,带有 Enum
,后面的所有值 = 传递给该数据类型的构造函数。例如::
>>> class MyEnum(IntEnum):
... example = '11', 16 # '11' will be interpreted as a hexadecimal
... # number
>>> MyEnum.example
<MyEnum.example: 17>
布尔值 Enum
类和成员¶
Enum
与非 -Enum
类型(如 int
, str
等)根据混合类型的规则进行计算;否则,所有成员的计算结果为 True
. 若要使自己的枚举的布尔值取决于成员的值,请将以下内容添加到类中:
def __bool__(self):
return bool(self.value)
Enum
使用方法的类¶
如果你把你的 Enum
子类附加方法,如 Planet 上面的类,这些方法将显示在 dir()
成员,但不属于该类:
>>> dir(Planet)
['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__members__', '__module__']
>>> dir(Planet.EARTH)
['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', 'surface_gravity', 'value']
组合的成员 Flag
¶
迭代Flag成员的组合将仅返回由单个位组成的成员::
>>> class Color(Flag):
... RED = auto()
... GREEN = auto()
... BLUE = auto()
... MAGENTA = RED | BLUE
... YELLOW = RED | GREEN
... CYAN = GREEN | BLUE
...
>>> Color(3)
<Color.YELLOW: 3>
>>> Color(7)
<Color.RED|GREEN|BLUE: 7>
StrEnum
and str.__str__()
¶
两者之间的一个重要区别 StrEnum
其他枚举是 __str__()
方法;因为 StrEnum
成员是字符串,Python的某些部分将直接读取字符串数据,而其他部分将调用 str()
. 为了使这两个操作有相同的结果, StrEnum.__str__()
将与 str.__str__()
以便 str(StrEnum.member) == StrEnum.member
是真的。
Flag
和 IntFlag
细节点¶
代码示例::
>>> class Color(IntFlag):
... BLACK = 0
... RED = 1
... GREEN = 2
... BLUE = 4
... PURPLE = RED | BLUE
... WHITE = RED | GREEN | BLUE
...
单位标志是规范的
多位和零位标志是别名
迭代期间仅返回规范标志::
>>> list(Color.WHITE) [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
否定标志或标志集将返回具有相应正整数值的新标志/标志集::
>>> Color.GREEN <Color.GREEN: 2> >>> ~Color.GREEN <Color.PURPLE: 5>
伪标志的名称由其成员名称构成::
>>> (Color.RED | Color.GREEN).name 'RED|GREEN'
多位标志(也称为别名)可以从以下操作返回::
>>> Color.RED | Color.BLUE <Color.PURPLE: 5> >>> Color(7) # or Color(-1) <Color.WHITE: 7>
成员身份/包容检查已稍有更改-从不将零值标志视为包含::
>>> Color.BLACK in Color.WHITE False
否则,如果一个标志的所有位都在另一个标志中,则返回True::
>>> Color.PURPLE in Color.WHITE True
有一种新的边界机制可以控制如何处理超出范围/无效的位: STRICT
, CONFORM
, EJECT
,以及 KEEP
:
Strict-->在显示无效值时引发异常
Conform-->丢弃任何无效位
弹出-->丢失标志状态,变成具有给定值的正常整型
- 保留-->保留多余的位
保留标志状态和额外位
多余的位不会在迭代中显示
额外的位确实会出现在repr()和str()中
标志的默认值为 STRICT
,默认设置为 IntFlag
是 DISCARD
,和的默认设置为 _convert_
是 KEEP
(请参阅 ssl.Options
有关以下情况的示例,请参阅 KEEP
是必需的)。