Python 进阶语法:enum(枚举)

1  枚举概述

1.1  枚举类型的产生

计算机里面的一些数据结构是为了反映现实生活中的各种各样的事物,以及事物与事物之间关系的。那么,现实世界中的类型概念在编程语言里应该如何来描述呢?

我们最常见的描述类型的方式会用一些数字来描述,比如,1表示男,2表示女。我们也经常会把这些数字存储在我们的数据库里,每个数字代表一种类型。

这种描述类型的方法非常简洁,但也有缺点。缺点在于,当我们读到这些数字的时候,我们无法知道这些数字究竟表示什么类型。因为数字本身不具备描述性。所以,用数字表示类型的方式,极大的破坏了编程代码的可阅读性。

在我们学过的数据类型里面,用字典表示类型比较合适,如:{’男‘:1,’女‘:2}。但字典并不是最优的一个数据类型。

为了解决这个问题,最主要的问题是为一组相关的常量值提供一个清晰、有意义的名称,而不是使用魔术数字或字符串。枚举类型应运而生。

1.2  什么是枚举

枚举在数学和计算机科学理论中,通常指列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。

在日常生活中,枚举也非常常见,例如表示星期的SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY就是一个枚举。枚举是一种特殊的类,它只包含一组有限的、特定的对象,且这些对象通常为只读。

在编程语言中,枚举是一种用户定义的类型,它包含了一组具名的值。这些值在定义后通常就不能改变。例如,在C#或Java中,可以定义一个表示颜色的枚举,包含Red、Green、Blue等值。然后,在程序中就可以使用这些预定义的颜色值,而不是使用魔数(即没有明确定义的数字常量)。

总的来说,枚举是一种非常有用的工具,它可以帮助程序员更清晰地表达他们的意图,提高代码的可读性和可维护性。

1.3  枚举的特点

枚举类型的特点主要包括以下几点:

  1. 有限性:枚举类型的值集合是固定的,即在定义枚举类型时,必须明确列举出其所有可能的取值,而且这些取值在程序运行期间是不能改变的。
  2. 不可变性:枚举类型的每个值在程序运行期间是不能改变的
  3. 有名性:枚举类型的每个值都有一个对应的名称,这使得代码更易于理解和维护。
  4. 常量性:枚举类型的值通常是常量,一旦定义,其值就不能被改变。
  5. 类型安全:使用枚举类型可以提高代码的类型安全性,因为它限制了变量只能取预定义的值。
  6. 便于管理:当需要添加或删除枚举值时,只需要修改枚举类型的定义即可,而不需要修改使用这些枚举值的代码。
  7. 简洁性:使用枚举类型可以简化代码,提高代码的可读性和可维护性。

这些特点使得枚举类型在编程中非常有用,特别是在需要定义一组固定的、相关的常量值时。通过使用枚举类型,我们可以为这些常量值提供有意义的名称,从而提高代码的可读性和可维护性。同时,枚举类型还可以提高代码的类型安全性和可管理性。

2  编程时,引入枚举类型库的意义

2.1  代码可读性和可维护性

枚举类型通过提供描述性的名称来替代数字或字符串常量,从而增加了代码的可读性。这使得其他开发者更容易理解代码的功能和目的。此外,当需要修改或扩展枚举值时,只需在一个地方进行修改,而不是在整个代码库中搜索和替换,这有助于提高代码的可维护性。

2.2  类型安全

枚举类型在编程中提供了强大的类型安全功能。通过使用枚举类型,开发者可以确保变量只能取预定义的一组值,这有助于在编译时(对于动态类型语言如Python,这实际上是在运行时)捕获类型错误,并减少因类型不匹配而引发的错误。

2.3  减少错误

枚举类型通过确保枚举成员的唯一性来减少错误。由于每个枚举成员都具有唯一的标识符和值,因此无法为同一个枚举类型创建具有相同值的成员。这有助于防止由于错误地使用了错误的值而导致的逻辑错误或意外行为。

2.4  支持迭代和比较

枚举类型通常支持迭代和比较操作,这使得在程序中操作枚举成员变得更加方便。开发者可以轻松地遍历枚举类型中的所有成员,并比较不同枚举成员的值。

2.5  提高性能

在某些情况下,使用枚举类型可能会提高程序的性能。例如,由于枚举成员的地址是唯一的,因此可以使用“==”操作符直接比较两个枚举成员的值,而不需要调用额外的比较方法。

2.6  扩展性和灵活性

枚举类型通常具有良好的扩展性和灵活性。开发者可以根据需要添加新的枚举成员或修改现有成员的值,而无需对整个代码库进行大规模的修改。

总之,引入枚举类型的库可以提高代码的可读性、可维护性和类型安全性,减少错误,提高性能,并支持更好的扩展性和灵活性。这使得枚举类型成为编程中一种非常有用的工具。

3  Python中的枚举(enum库)

enum 是Python 3.4及更高版本中引入的一个标准库,它提供了一个枚举类型,可以让我们定义具有固定数量值的数据类型。使用enum可以提高代码的可读性和可维护性,因为它允许我们为值赋予有意义的名称,而不是使用可能令人困惑的数字或字符串常量。

 3.1  导入enum库

在Python中,你需要导入enum库才能使用它。你可以通过以下方式导入整个库或仅导入你需要的部分。

import enum
from enum import Enum, auto

3.2  定义枚举类型

通过继承 enum.Enum 类并为其添加类变量,可以定义一个新的枚举类型。每个类变量都表示该枚举类型的一个值。

import enum
class Color(enum.Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

Enum 是基本的枚举类,用于创建具有任意类型值的枚举。在这个例子中,我们定义了一个名为Color的枚举类型,它有三个值:RED、GREEN和BLUE。每个值都与一个整数相关联,但你也可以使用其他数据类型(如字符串)。

from enum import IntEnum
# 具有整数值的枚举类型
class StatusCode(IntEnum):
    OK = 200
    BAD_REQUEST = 400
    NOT_FOUND = 404 

IntEnum 是 Enum 的子类,用于创建具有整数值的枚举。IntEnum 成员可以用作整数,并且支持比较运算。 

3.3  使用枚举类型

3.3.1  通过枚举类型获取枚举成员的名称和值
import enum
class Color(enum.Enum):
    RED = 1
    GREEN = 2
    BLUE = 3
print(type(Color.RED))  #  说明这是一个枚举类型
# 通过枚举类型获取枚举成员名称和值
color = Color.RED  # 枚举类型
print(color.name)  # 输出: RED
print(color.value) # 输出:1
3.3.2  遍历枚举类型的所有成员
import enum
class Color(enum.Enum):
    RED = 1
    GREEN = 2
    BLUE = 3
# 遍历枚举类型的所有成员
for color in Color:
    print(color)  # 输出: Color.RED, Color.GREEN, Color.BLUE
3.3.3  使用auto()函数自动生成值

auto()是一个帮助函数,用于自动生成唯一的整数值。当你不想显式地为枚举成员指定值时,这很有用。

from enum import Enum,IntEnum,auto,unique
# 使用 auto() 自动生成值
class AutoName(Enum):
    FIRST = auto()
    SECOND = auto()
    THIRD = auto()
for n in AutoName:
    print(n.name,n.value)
    
# 返回结果:
# FIRST 1
# SECOND 2
# THIRD 3
3.3.4  使用@unique装饰器,确保枚举中没有重复的值

@unique 是一个装饰器,用于确保枚举中没有重复的值。如果有重复的值,它将引发一个错误。

from enum import Enum, IntEnum, auto, unique
# 使用 @unique 装饰器确保没有重复值
@unique
class Response(Enum):
    ACK = 1
    NACK = 2
    IGNORE = 1  # 这将引发一个错误,因为值不唯一
 3.3.5 检查枚举成员是否存在
from enum import Enum
class StatusCode(Enum):
    OK = 200
    BAD_REQUEST = 400
    NOT_FOUND = 404
# 检查枚举成员是否存在
if StatusCode.OK in StatusCode:
    print("OK is a member of StatusCode")
3.3.6 枚举类型的比较

枚举类型的目的是为了定义一组有限的、命名的常量,而不是为了支持数学运算或排序。如果你需要比较 Enum 成员枚举值,通常应该使用 == 或 != 运算符来检查它们是否相等或不相等。

from enum import Enum
class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3
# 枚举类型的比较
if Color.RED != Color.GREEN:
    print("RED is not the same as GREEN")
3.3.7  枚举类型的比较和运算

IntEnum 成员可以用作整数,并且支持比较运算。

from enum import IntEnum
class StatusCode(IntEnum):
    OK = 200
    BAD_REQUEST =400
    NOTFIND = 404
# IntEnum 支持整数运算
if StatusCode.OK < StatusCode.BAD_REQUEST:
    print("OK has a lower value than BAD_REQUEST")
# 返回:OK has a lower value than BAD_REQUEST
difference = StatusCode.BAD_REQUEST-StatusCode.OK
print(difference)
# 返回:200