# 枚举类Enum

***

## 枚举类Enum

### **枚举类有哪些好处**

> 枚举类可以方便地表示星期，月份等常数类型，如果你不用枚举类，那么你只能用数字或者字符串。如果你使用数字，用1-7来表示星期数，但一个数字在程序中不仅可以表示星期数，可能还有其他许多含义，这样你在写程序时就必须时刻记住这些数字的含义，这降低了程序的可读性，也导致容易出错。而当你使用字符串时，虽然没有明显的缺点，但在内存中字符串所占内存要比数字多，这就降低了程序的效率。
>
> 枚举类正好弥补了这两方面的缺点，你可以在代码中使用枚举类，但在内存中存放时使用的是数字，既提高了可读性，又提高了程序效率。更重要的是，Python中的枚举类型是不可变类型，又可以进行迭代，这就意味着你可以随时使用枚举类型而不用担心改变了枚举类型的值。

### 两种枚举类定义方式

> 程序有两种方式来定义枚举类：
>
> 1. 直接使用 Enum 列出多个枚举值来创建枚举类。
> 2. 通过继承 Enum 基类来派生枚举类。

## 案例

### 简单枚举类定义

```python
# 由于枚举类的“new”方法，将会保证内存中只会存在一个枚举类的实例
# -*- coding: utf-8 -*
from enum import Enum

# 这样我们就获得了Month类型的枚举类
# value属性则是自动赋给成员的int常量，默认从1开始计数。
seasonEnum = Enum('SeasonEnum', ('SPRING', 'SUMMER', 'FALL', 'WINTER'))
print(f'seasonEnum: {seasonEnum}')
```

### 高级枚举类定义

> 代码

```python
from enum import Enum, unique
# @unique装饰器可以帮助我们检查保证没有重复值。
# 冬天 = 3这里就会报错，否则SeasonEnum.__members__.items，会把
# WINTER => SeasonEnum.WINTER
# 冬天 => SeasonEnum.WINTER
# 装饰器“@unique”，它会遍历枚举成员，如果发现有重复就会立即抛出“ValueError”
@unique
class SeasonEnum(Enum):
    # SPRING = auto() # 也可以全部使用自动值
    SPRING = 0  # Sun的value被设定为0
    SUMMER = 1
    FALL = 2
    WINTER = 3
    # 冬天 = 3

# 访问这些枚举类型可以有若干种方法：
season_1 = SeasonEnum.SPRING
print(f'season_1: {season_1}')
print(f"SeasonEnum['SPRING']: {SeasonEnum['SPRING']}")
print(f'SeasonEnum.SPRING.value: {SeasonEnum.SPRING.value}')
print(f'SeasonEnum(1): {SeasonEnum(1)}')
print(f'season_1 == SeasonEnum(1): {season_1 == SeasonEnum(1)}')    
```

> 输出

```python
seasonEnum: <enum 'SeasonEnum'>
season_1: SeasonEnum.SPRING
SeasonEnum['SPRING']: SeasonEnum.SPRING
SeasonEnum.SPRING.value: 0
SeasonEnum(1): SeasonEnum.SUMMER
season_1 == SeasonEnum(1): False
```

### 枚举类比较

> 代码

```python
# 枚举类型不能做大小比较，但是可以做身份比较和等值比较。
print(f'SeasonEnum.SPRING is SeasonEnum.SPRING: {SeasonEnum.SPRING is SeasonEnum.SPRING}')
print(f'SeasonEnum.SPRING is SeasonEnum.WINTER: {SeasonEnum.SPRING is SeasonEnum.WINTER}')
# 这是身份比较，每个对象都可以进行身份比较，枚举类也不例外。
print(f'SeasonEnum.SPRING == SeasonEnum.SPRING: {SeasonEnum.SPRING == SeasonEnum.SPRING}')
print(f'SeasonEnum.SPRING != SeasonEnum.WINTER: {SeasonEnum.SPRING != SeasonEnum.WINTER}')

```

> 输出

```cmd
SeasonEnum.SPRING is SeasonEnum.SPRING: True
SeasonEnum.SPRING is SeasonEnum.WINTER: False
SeasonEnum.SPRING == SeasonEnum.SPRING: True
SeasonEnum.SPRING != SeasonEnum.WINTER: True
```

### 遍历枚举类

> 代码

```python
# 如果尝试遍历枚举类型，则后面重复的不会被打印出来。但是，如果想要获取别名，
# 我们可以使用属性“members”，它是一个OrderedDict，包括所有定义的枚举名称，包括别名。
for name, member in SeasonEnum.__members__.items():
    print(name, '=>', member)

for name, member in enumerate(SeasonEnum):
    print(name, '=>', member) 
```

> 输出

```python
SPRING => SeasonEnum.SPRING
SUMMER => SeasonEnum.SUMMER
FALL => SeasonEnum.FALL
WINTER => SeasonEnum.WINTER


0 => SeasonEnum.SPRING
1 => SeasonEnum.SUMMER
2 => SeasonEnum.FALL
3 => SeasonEnum.WINTER    
```
