枚举 enum
以下内容基本来自python官方文档,有兴趣的同学可以去查看原文档
枚举表示的是常量,因此,建议枚举成员名称使用大写字母。
本模块定义了四个枚举类,用来定义名称与值的唯一组合: Enum
、IntEnum
、Flag
和 IntFlag
。此外,还定义了一个装饰器,unique()
, 和一个辅助类,auto
1. 定义一个基础的枚举类
枚举是由 class
句法创建的,这种方式易读、易写。
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
注解:成员值(如上例中的1,2,3)可以是 int
、str
等。若无需设定确切值,auto
实例可以自动为成员分配合适的值。将 auto
与其他值混用时必须要慎重。
注解:虽然 Enum 由 class
语法创建,但 Enum 并不是常规的 Python 类。
注解:
-
Color.RED
、Color.GREEN
等属性是 枚举成员 (或 enum 成员),也是常量。 - 枚举成员具有 名称 和 值 (例如
Color.RED
的名称为RED
,Color.BLUE
的值为3
等等)
枚举成员的字符串表现形式更容易理解
In [16]: print(Color.RED)
Color.RED
同时,它的 repr 包含更多信息:
In [18]: print(repr(Color.RED))
<Color.RED: 1>
枚举成员的 类型 就是它所属的枚举:
In [19]: type(Color.RED)
Out[19]: <enum 'Color'>
In [20]: isinstance(Color.GREEN, Color)
Out[20]: True
Enum 成员还包含 name 和 value 属性:
In [21]: Color.RED.name
Out[21]: 'RED'
In [22]: Color.RED.value
Out[22]: 1
枚举按定义的顺序进行迭代:
这里可以看出,枚举类和普通的python类是不一样的,遍历这点就不同。
In [23]: for color in Color:
...: print(color)
...:
Color.RED
Color.GREEN
Color.BLUE
枚举成员可哈希,可用于字典和集合:
In [24]: apples = {}
In [25]: apples[Color.RED] = 'red delicious'
In [26]: apples[Color.GREEN] = 'granny smith'
In [27]: apples == {Color.RED: 'red delicious', Color.GREEN: 'granny smith'}
Out[27]: True
2. 枚举成员及其属性的访问
有时,要在程序中访问枚举成员(如,开发时不知道颜色的确切值,Color.RED
不适用的情况)。Enum 支持如下访问方式:
In [28]: Color(1)
Out[28]: <Color.RED: 1>
In [29]: Color(3)
Out[29]: <Color.BLUE: 3>
用 name 访问枚举成员时,可使用项目名称:
In [30]: Color['RED']
Out[30]: <Color.RED: 1>
In [31]: Color['GREEN']
Out[31]: <Color.GREEN: 2>
可访问枚举成员的 name 或 value:
In [32]: member = Color.RED
In [33]: member.name
Out[33]: 'RED'
In [34]: member.value
Out[34]: 1
3. 重复的枚举成员和值
两个枚举成员的名称不能相同:
In [35]: class Shape(Enum):
...: SQUARE = 2
...: SQUARE = 3
...:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
...
TypeError: Attempted to reuse key: 'SQUARE'
但是,两个枚举成员可以有相同的值。假设,成员 A 和 B 的值相同(先定义的是 A),则 B 是 A 的别名。按值查找 A 和 B 的值返回的是 A。按名称查找 B,返回的也是 A:
In [36]: class Shape(Enum):
...: SQUARE = 2
...: DIAMOND = 1
...: CIRCLE = 3
...: ALIAS_FOR_SQUARE = 2
...:
In [37]: Shape.SQUARE
Out[37]: <Shape.SQUARE: 2>
In [38]: Shape.ALIAS_FOR_SQUARE
Out[38]: <Shape.SQUARE: 2>
In [39]: Shape(2)
Out[39]: <Shape.SQUARE: 2>
4. 确保唯一枚举值
默认情况下,枚举允许多个名称作为一个值的别名。如需禁用此行为,下述装饰器可以确保枚举中的值仅能只用一次:
@enum.unique
In [40]: from enum import Enum, unique
In [41]: @unique
...: class Mistake(Enum):
...: ONE = 1
...: TWO = 1
...:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
...
ValueError: duplicate values found in <enum 'Mistake'>: TWO -> ONE
5. 使用自动设定的值
如果确切的值不重要,你可以使用 auto
:
In [42]: from enum import Enum, auto
In [43]: class Color(Enum):
...: RED = auto()
...: BLUE = auto()
...: GREEN = auto()
...:
In [44]: list(Color)
Out[44]: [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]
值将由 generate_next_value() 来选择,该函数可以被重载:
In [45]: 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()
...:
In [46]: list(Ordinal)
Out[46]:
[<Ordinal.NORTH: 'NORTH'>,
<Ordinal.SOUTH: 'SOUTH'>,
<Ordinal.EAST: 'EAST'>,
<Ordinal.WEST: 'WEST'>]
Enum中有 _generate_next_value_
方法,这里被覆盖。
6. 迭代
对枚举成员的迭代不会迭代出别名部分:
In [47]: list(Shape)
Out[47]: [<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
特殊属性 __members__
是一个从名称到成员的只读有序映射。 它包含枚举中定义的所有名称,包括别名:
In [49]: for name, member in Shape.__members__.items():
...: print(name, member)
...:
...:
SQUARE Shape.SQUARE
DIAMOND Shape.DIAMOND
CIRCLE Shape.CIRCLE
ALIAS_FOR_SQUARE Shape.SQUARE
__members__
属性可被用于对枚举成员进行详细的程序化访问。 例如,找出所有别名:
In [50]: [name for name, member in Shape.__members__.items() if member.name != name]
Out[50]: ['ALIAS_FOR_SQUARE']
7. 比较
枚举成员是按标识号进行比较的:
In [51]: Shape.SQUARE is Shape.SQUARE
Out[51]: True
In [52]: Shape.SQUARE is Shape.CIRCLE
Out[52]: False
# 和别名相等
In [53]: Shape.SQUARE is Shape.ALIAS_FOR_SQUARE
Out[53]: True
枚举值之间的排序比较 不被 支持。 Enum 成员不属于整数。即不能进行 >
和 <
比较。
In [55]: Shape.SQUARE > Shape.CIRCLE
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-55-811bd6fff84e> in <module>
----> 1 Shape.SQUARE > Shape.CIRCLE
TypeError: '>' not supported between instances of 'Shape' and 'Shape'
相等比较的定义如下:
In [56]: Shape.SQUARE == Shape.CIRCLE
Out[56]: False
In [57]: Shape.SQUARE != Shape.CIRCLE
Out[57]: True
In [58]: Shape.SQUARE == Shape.ALIAS_FOR_SQUARE
Out[58]: True
与非枚举值的比较将总是不相等
In [59]: Shape.SQUARE == 2
Out[59]: False
8. 允许的枚举成员和属性
以上示例使用整数作为枚举值。 如果值 确实 重要,则枚举可以使用任意的值。
枚举属于 Python 的类,并可具有普通方法和特殊方法。 如果我们有这样一个枚举:
class Mood(Enum):
FUNKY = 1
HAPPY = 3
def describe(self):
# self is the member here
# 在这里self 表示枚举的成员
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
# 在这里cls表示枚举对象
return cls.HAPPY
那么:
In [61]: Mood.favorite_mood()
Out[61]: <Mood.HAPPY: 3>
In [62]: Mood.HAPPY.describe()
Out[62]: ('HAPPY', 3)
In [63]: str(Mood.FUNKY)
Out[63]: 'my custom str! 1'
9. 封存
枚举可以被封存与解封:
In [65]: from pickle import dumps, loads
In [66]: Color is loads(dumps(Color))
Out[66]: True
10. 功能性 API
Enum
类属于可调用对象,它提供了以下功能性 API:
In [67]: Animal = Enum('Animal', 'ANT BEE CAT DOG')
In [68]: Animal
Out[68]: <enum 'Animal'>
In [69]: Animal.ANT
Out[69]: <Animal.ANT: 1>
In [70]: Animal.ANT.value
Out[70]: 1
In [71]: list(Animal)
Out[71]: [<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]
第一个参数是枚举的名称。
第二个参数是枚举成员名称的 来源。 它可以是一个用空格分隔的名称字符串、名称序列、键/值对 2 元组的序列,或者名称到值的映射(例如字典)。 最后两种选项使得可以为枚举任意赋值;其他选项会自动以从 1 开始递增的整数赋值(使用 start 形参可指定不同的起始值)。
11. 派生的枚举
IntEnum
所提供的第一个变种 Enum
同时也是 int
的一个子类。 IntEnum
的成员可与整数进行比较;通过扩展,不同类型的整数枚举也可以相互进行比较:
In [72]: from enum import IntEnum
...: class Shape(IntEnum):
...: CIRCLE = 1
...: SQUARE = 2
...:
...: class Request(IntEnum):
...: POST = 1
...: GET = 2
...:
In [73]: Shape == 1
Out[73]: False
In [74]: Shape.CIRCLE == 1
Out[74]: True
In [75]: Shape.CIRCLE == Request.POST
Out[75]: True
不过,它们仍然不可与标准 Enum
枚举进行比较:
In [76]: class Shape(IntEnum):
...: CIRCLE = 1
...: SQUARE = 2
...:
...: class Color(Enum):
...: RED = 1
...: GREEN = 2
...:
In [77]: Shape.CIRCLE == Color.RED
Out[77]: False
IntEnum
值在其他方面的行为都如你预期的一样类似于整数:
In [78]: int(Shape.CIRCLE)
Out[78]: 1
In [79]: ['a', 'b', 'c'][Shape.CIRCLE]
Out[79]: 'b'
In [80]: [i for i in range(Shape.SQUARE)]
Out[80]: [0, 1]
IntFlag
未完待续。。。