Python 入门(六)- 枚举专题

如果想表示枚举,可以用哪些方式呢?以下是我们能想到的可用来表示枚举的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 方法一
yellow = 1
green =2

# 方法二
a = {
'yellow': 1,
'green': 2
}

# 方法三
class Type():
yellow = 1
green = 2

上述三种方法都存在着不足,例如:枚举变量可变,且没有防止相同值的功能。

1
2
3
4
5
6
7
8
9
# 枚举变量可变
a['yellow'] = 3
Common.YELLOW = 3

# 相同值
a = {
'yellow': 1,
'green': 1
}

枚举其实是个类

python2中没有枚举类型,python3中增加了枚举类型。所有的枚举类型都是 Enum 的子类。建议枚举类中所有的属性名称均为大写。

枚举类和普通类的区别在于:访问枚举属性时,并无法打印出属性值,而是返回类名.属性名

枚举与普通类的区别:

  • 枚举类中变量不可重新赋值
  • 枚举类不能具有相同标签的,但可以具有相同的枚举值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from enum import Enum

class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4

# 访问枚举
VIP.BLACK
print(VIP.YELLOW) # VIP.YELLOW,并非 1

# 修改枚举类中的值
VIP.YELLOW = 6 # 报错,起保护作用

这里需要注意的是枚举类可以具有相同的枚举值,重复的枚举值对应的枚举名的别名。在下例中,VIP.GREEN被认为是VIP.YELLOW的别名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from enum import Enum

class VIP(Enum):
YELLOW = 1
GREEN = 1 # 等同于 YELLOW_ALIAS

print(VIP.GREEN) # VIP.YELLOW

# 常规遍历
for v in VIP:
print(v)

### output
VIP.YELLOW # GREEN不会被打印出来

# 遍历
for v in VIP.__members__.items():
print(v)

### output
('YELLOW', <VIP.YELLOW: 1>)
('GREEN', <VIP.YELLOW: 1>) # GREEN会被打印出来

# 遍历
for v in VIP.__members__:
print(v)

### output
YELLOW
GREEN # GREEN会被打印出来

枚举类型、枚举名称与枚举值

访问枚举值:value属性
访问枚举名称:name属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from enum import Enum

class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4

print(VIP.GREEN.value) # 2 获取值
print(VIP.GREEN.name) # GREEN 获取名称
print(VIP.GREEN) # VIP.GREEN

# VIP.GREEN.name与VIP.GREEN的区别
print(type(VIP.GREEN.name)) # <class 'str'>
print(type(VIP.GREEN)) # <enum 'VIP'>

print(VIP['GREEEN']) # VIP.GREEN

枚举是可以遍历的

1
2
3
4
5
6
7
8
for v in VIP:
print(v)

# output
VIP.YELLOW
VIP.GREEN
VIP.BLACK
VIP.RED

枚举的比较运算

枚举可以进行如下比较运算:

  • 等值比较(==)
  • 身份比较(is)

枚举无法进行如下比较运算:

  • 大小比较(<,>)

枚举类内部变量的比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from enum import Enum

class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4

# 等值比较
result = VIP.GREEN == VIP.BLACK
print(result) # False

result = VIP.GREEN == VIP.GREEN
print(result) # True

result = VIP.GREEN == 2
print(result) # False

# 枚举类型不支持不等值比较
result = VIP.GREEN > VIP.BLACK
print(result) # 报错,TypeError: '>' not supported between instances of 'VIP' and 'VIP'

# 身份比较 is
result = VIP.GREEN is VIP.GREEN
print(result) # True

枚举类之间的比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from enum import Enum

class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4

class VIP1(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4

result = VIP.GREEN == VIP1.GREEN
print(result) # False 非相同的枚举类

枚举转换

编写代码时,尽量不用枚举值,而使用枚举名称,更具有可读性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from enum import Enum

class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4

a = 1

# 推荐写法
if a == VIP.YELLOW:
print('xxx')

# 不推荐写法
if a == 1:
print('xxx')

# 枚举转换,使用数值来访问名称
print(VIP(a)) # VIP.YELLOW

枚举的其他一些碎碎念

IntEnum

当枚举值中不允许出现字符串,只能是整形时,可继承 IntEnum 类。

例如在下例中,由于'str'为字符串类型,则代码会报错。

1
2
3
4
5
6
7
8
from enum import IntEnum

class VIP(IntEnum):
YELLOW = 1
GREEN = 'str'

### output
ValueError: invalid literal for int() with base 10: 'str'

@unique 装饰器

如果希望避免一个枚举类中存在相同的枚举值,则可增加@unique装饰器。在下例中,由于YELLOW和GREEN都有相同的

1
2
3
4
5
6
7
8
9
from enum import IntEnum,unique

@unique
class VIP(IntEnum):
YELLOW = 1
GREEN = 1

### output
ValueError: duplicate values found in <enum 'VIP'>: GREEN -> YELLOW

单例模式

枚举是单例模式,不能进行实例化。