为什么需要枚举?枚举是用来定义常量的。枚举元素具有不可变的特性,可以用来充当常量。
枚举是与唯一常量值绑定的一系列符号名称(成员)的集合。枚举中的元素可以进行恒等比较,并且枚举本身可迭代。
例如,对于圆周率,我们在 Python 中简单定义 PI = 3.14
,但 PI
是变量,是可以被修改的,故更严格地定义常量需要用到枚举。本文是对 Python 内置枚举模块 enum 的讲解。
注解:枚举成员名称的大小写因为枚举是用来表示常量的,因此,枚举成员名称建议使用大写字母,本文的示例将采用此种风格。
enum及其子类
python的枚举类型是继承enum模块的Enum类,定义自己的枚举类,枚举元素相当于类变量
from enum import Enum
class colorEnum(Enum):
red = 1
yellow = 2
blue = 3
# 方法2:
from enum import Enum
Month = Enum('month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
enum模块子类
enum
模块定义了四个枚举类,用来定义名称与值的唯一组合:Enum
、IntEnum
、Flag
和IntFlag
。此外,还定义了一个装饰器 unique()
和一个辅助类 auto
。
class enum.Enum
:创建枚举常量的基类。class enum.IntEnum
:创建int
子类枚举常量的基类。class enum.Flag
:创建可与位运算符搭配使用,而又不失去Flag
成员资格的枚举常量的基类。class enum.IntFlag
:创建可与位运算符搭配使用,而又不失去IntFlag
成员资格的枚举常量的基类。enum.unique()
:Enum
类的装饰器,确保一个名称只绑定一个值。class enum.auto
:用合适的值代替Enum
成员的实例。初始默认值从1
开始。
新建枚举
枚举是用 class
语法创建的,这种方式易读、易写。利用子类 Enum
定义枚举方法如下:
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
# 方法2:
from enum import Enum
Month = Enum('month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
注解:Enum
成员值成员值可以是 int
、str
等。若无需设定确切值,auto
实例可以自动为成员分配合适的值。将 auto
和其它值混用需慎重。
注解:命名法
- 类
Color
是枚举(Enum
)。 Color.RED
、Color.GREEN
等属性是枚举成员(Enum
成员),也是常量。- 枚举成员具有名称和值(例如
Color.RED
的名称为RED
,Color.BLUE
的值为3等等)。
注解:虽然 Enum
由 class
语法创建,但 Enum
并不是常规的 Python 类。
重复问题
value重复
默认情况下,不同的成员值允许相同。但是两个相同值的成员,第二个成员的名称被视作第一个成员的别名
from enum import Enum
class BaseFunc(Enum):
name = "张三"
names = "张三"
age = 25
sex = '男'
data_name = BaseFunc.name
data_names = BaseFunc.names
print(data_name)
print(data_names)
print(data_name.value)
print(data_names.value)
枚举类型是name=value的形式,name是不能重复,value可以重复,但是重复的值的别名是第一个的:
from enum import Enum
class colorEnum(Enum):
red = 1
yellow = 2
blue = 3
gray = 1
print(colorEnum.red)
print(colorEnum.gray)
name重复
定义枚举时,成员名称不允许重复,成员名称相同时就会报错。
from enum import Enum
from types import DynamicClassAttribute
class BaseFunc(Enum):
name = "dgw"
age = 25
sex = '男'
# 父类Enum中的方法
@DynamicClassAttribute
def new_name(self):
"""The name of the Enum member."""
return self._name_
data1 = list(map(lambda x: x.name, BaseFunc))
print(data1)
data2 = list(map(lambda x: x.new_name, BaseFunc))
print(data2)
unique确保唯一
默认情况下,枚举允许多个枚举成员具有相同的值。如需禁用此行为,可以使用装饰器 @enum.unique
from enum import Enum, unique
@unique
class colorEnum(Enum):
red = 1
yellow = 2
blue = 3
gray = 1
"""
ValueError: duplicate values found in <enum 'colorEnum'>: gray -> red
"""
自动赋值
enum.auto()
函数可自动为枚举成员分配值:
from enum import Enum, auto
class Color(Enum):
RED = auto()
GREEN = auto()
BLUE = auto()
print(list(Color)) # [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 3>]
枚举类型的使用
枚举类的取值
- 可通过名索引访问
- 可通过值索引访问
- 获取枚举成的 name 和 value
枚举类名.变量名
直接获取枚举值枚举类名(value)
根据枚举value获取枚举值变量,value可以是实际的数字、字符串等枚举类名(name).value
获取枚举value
from enum import Enum
class colorEnum(Enum):
red = 1
yellow = 2
blue = 3
print(colorEnum.red) # colorEnum.red
print(type(colorEnum.red)) # <enum 'colorEnum'>
print(colorEnum.red.value) # 1
print(type(colorEnum.red.value)) # <class 'int'>
print(colorEnum(1)) # colorEnum.red
获枚举取值
枚举变量是name=value的形式
可以使用value取值value或者name
可以使用name变量去取值value或者name
from enum import Enum
class colorEnum(Enum):
red = 1
yellow = 2
blue = 3
print(colorEnum(1))
print(colorEnum(1).value)
print(colorEnum["red"])
print(colorEnum["red"].value)
"""
colorEnum.red
1
colorEnum.red
1
"""
获取枚举的names和values
使用魔法方法__members__获取values和names,结果是dict数组
from enum import Enum
class colorEnum(Enum):
red = 1
yellow = 2
blue = 3
print(colorEnum.__members__.values())
print(colorEnum.__members__.keys())
"""
dict_values([<colorEnum.red: 1>, <colorEnum.yellow: 2>, <colorEnum.blue: 3>])
dict_keys(['red', 'yellow', 'blue'])
"""
举例:
判断变量是否在我们枚举类中,在的话打印出值:
colors=["red","blue","pink"]
for color in colors:
if color in colorEnum.__members__.keys():
print(colorEnum[color].value)
"""
1
3
"""
枚举值value:name的映射函数:_value2member_map_
from enum import Enum
class colorEnum(Enum):
red = 1
yellow = 2
blue = 3
print(colorEnum._value2member_map_)
"""
red
yellow
"""
枚举类的遍历
# 方法一:
for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)
# 方法二:
# 枚举支持迭代器,可以遍历枚举成员
for v in Mon:
print(v)
如果枚举有值重复的成员,循环遍历枚举时只获取值重复成员的第一个成员
from enum import Enum
class BaseFunc(Enum):
name = "张三"
names = "张三"
age = 25
sex = '男'
for value in BaseFunc:
print(value, value.name, value.value)
如果想把值重复的成员也遍历出来,要用枚举的一个特殊属性__members__
from enum import Enum
class BaseFunc(Enum):
name = "张三"
names = "张三"
age = 25
sex = '男'
for value in BaseFunc.__members__.items():
print(value)
比较大小
枚举成员间不允许比较大小
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
print(Color.RED < Color.BLUE) # TypeError: '<' not supported between instances of 'Color' and 'Color'
与非枚举值的比较总不相等:
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
print(Color.RED == 1) # False
混合枚举
from enum import Enum
# 通过多重继承创建支持整数比较的枚举
class Size(int, Enum):
S = 1
M = 2
L = 3
XL = 4
print(Size.S > Size.M)
# 实现和上述代码一样的功能
from enum import IntEnum
# 通过IntEnum创建支持整数比较的枚举
class Size(IntEnum):
S = 1
M = 2
L = 3
XL = 4
print(Size.S > Size.M) # False
基于位掩码的枚举类型enum.Flag
from enum import IntFlag, Flag, auto
# 创建基于位掩码的枚举类型,注意成员值为2的幂,最好不要自定义
# 如果想创建整数枚举继承IntFlag即可
class Permissions(Flag):
READ = auto() # 定义读权限
WRITE = auto() # 定义写权限
EXECUTE = auto() # 定义执行权限
DELETE = auto() # 定义删除权限
# 使用 name 和 value 属性获取枚举名称和值
# 可以看到各个成员的值是2的幂
for p in Permissions:
print(p.name, p.value)
# 使用枚举成员
perms_rw = Permissions.READ | Permissions.WRITE # 用户拥有读和写权限
# 可以看到perms_rw的值为3
print(perms_rw.name, perms_rw.value)
# 检查是否有某个权限
# 使用&运算符来判断一个枚举值中是否包含某个特定的枚举值
if perms_rw & Permissions.READ: # 如果用户拥有读权限
print("用户拥有读权限")
if perms_rw & Permissions.WRITE: # 如果用户拥有写权限
print("用户拥有写权限")
if perms_rw & Permissions.EXECUTE: # 如果用户拥有执行权限
print("用户拥有执行权限")
# 遍历所有权限
for perm in Permissions:
print(perm)
"""
READ 1
WRITE 2
EXECUTE 4
DELETE 8
None 3
用户拥有读权限
用户拥有写权限
Permissions.READ
Permissions.WRITE
Permissions.EXECUTE
Permissions.DELETE
"""