Python 中的枚举如何提高代码可读性

在多种编程语言中,例如C、C++和Java,枚举都是一种常用的数据类型。它们能够帮助开发者编写更安全、更具可读性的代码。

在Python早期版本中,枚举并非原生支持。然而,自3.4版本起,Python开始引入了枚举类型。本文将详细介绍如何在Python中创建枚举、如何使用它们,以及它们如何提升代码的可读性。

什么是枚举?它们的作用是什么?

枚举,或者说枚举类型,是一种通过它可以取值的集合来定义的数据类型。这个值集合被称为成员集。枚举使得你可以更精确地限定变量可以拥有的值,从而有助于编写类型安全的代码,并提高代码的可读性。

一些需要了解的术语

在讨论枚举时,我们首先需要明确一些术语,因为我们将在后续内容中频繁使用它们。这些术语包括“成员”和“值”。

  • 成员:指的是构成枚举值集合的具名常量。例如,一个表示星期的枚举(Days)可能包含“星期日”、“星期一”、“星期二”等成员。
  • 值:是在内部用来明确表示每个枚举成员的值。这使得进行比较成为可能。例如,在星期的枚举中,“星期日”的值可能为0,“星期一”的值为1,“星期二”的值为2,以此类推。

接下来,我们将探讨枚举是如何改善你的代码的。

枚举如何改进你的代码

枚举可以通过多种方式改进你的代码,使其更易于理解且不易出错。以下是一些你应该使用枚举的原因:

  • 枚举可以清晰地定义变量或函数参数可以接受的取值范围。通过明确表达变量或函数参数的预期值,可以使代码更容易被他人理解。
  • 枚举还可以使你的代码具有自我文档化的特性。这意味着你不需要额外添加注释或文档来指定函数期望的值,枚举本身就清晰地表达了这些信息。
  • 同时,集成开发环境(IDE)能够在传递错误值时提示错误,并提供自动补全支持。
  • 因此,你的代码会变得更具类型安全性,从而降低运行时错误的风险。

接下来,我们将讨论如何在Python中创建枚举。

如何在Python中创建枚举

Python自身并没有原生支持枚举类型,但在标准库中提供了`enum`模块。我们将在本教程中使用这个模块。在Python中,创建枚举有两种主要方法:使用类或者使用函数API。接下来我们将详细介绍这两种方法。

先决条件

为了学习本教程,你需要安装Python 3.4或更高版本。这个版本的Python在其标准库中包含了`enum`模块。如果你还没有安装,这里有一个教程可以帮助你:

此外,你需要具备一定的Python编程基础,包括基本的Python语法和一些面向对象编程的概念,例如类和继承。

#1. 类方法

创建枚举的第一种方式是使用类。首先,从`enum`模块导入`Enum`类。然后,通过创建一个继承自`Enum`类的类来定义枚举。

from enum import Enum

class Direction(Enum):
    NORTH = 0
    EAST = 1
    SOUTH = 2
    WEST = 3

你也可以为枚举的成员指定任何你想要的值。例如,我们可以不使用0、1、2和3来表示方向,而是使用它们对应的角度值:0、90、180和270。

from enum import Enum

class Direction(Enum):
    NORTH = 0
    EAST = 90
    SOUTH = 180
    WEST = 270

另外,使用`range`函数可以更简洁地生成上述代码。如下所示:

from enum import Enum

class Direction(Enum):
    NORTH, EAST, SOUTH, WEST = range(0, 360, 90)

在这个例子中,我们使用`range`函数生成一组值。起始值为0,结束值为360(不包含),步长为90。然后,我们解构了这个可迭代对象,这类似于解构元组。如果你想了解更多关于元组解构的信息,可以查阅关于Python中元组的文章。

枚举类是抽象类,这意味着它们不应该被实例化。相反,可以直接访问它们的属性(即枚举的成员)。

#2. 函数方法

函数方法是子类方法的替代方案。

from enum import Enum

Direction = Enum("Direction", ["NORTH", "EAST", "SOUTH", "WEST"])

在上面的代码片段中,我们创建了一个名为`Direction`的枚举,它有四个成员,这些成员作为第二个参数传递给`Enum`函数。默认情况下,这些成员的值从1开始分配,因此“NORTH”为1,“EAST”为2,以此类推。之所以从1开始而不是从0开始,是因为0在Python中被认为是false。为了使所有值都为true,这些值从1开始编号。

或者,你可以通过传递一个元组列表来为成员指定值。每个元组包含两个元素:成员的名称和该成员的值。

from enum import Enum

Direction = Enum(
    name = "Direction",
    values = [
        ("NORTH", "n"),
        ("EAST", "e"),
        ("SOUTH", "s"),
        ("WEST", "w"),
    ]
)

你会注意到,在上面的例子中,我使用字符串而不是整数作为成员的值。这说明字符串和整数都可以作为值来使用。

如何使用枚举

在前一节中,我们介绍了如何创建枚举以及如何为成员赋值。本节将介绍如何使用枚举来访问和分配成员,以及如何进行相等性检查。

如何访问成员

有多种方法可以访问枚举的成员,包括点语法、括号和方括号语法。以下是一个演示的例子:

from enum import Enum

# 创建一个枚举
class Day(Enum):
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY = range(1, 8)

# 访问枚举成员
# 1. 使用点语法
print(Day.SUNDAY)

# 2. 使用方括号
print(Day["MONDAY"])

# 3. 使用括号
print(Day(3))

在访问枚举成员后,你可以将其存储在变量中。请注意,访问成员会返回该成员对象的引用,而不是其值或名称。这一点在接下来的部分中非常重要。

访问名称和值

如前所述,当你访问枚举成员时,你会创建对该成员对象的引用。如果你需要访问枚举对象的名称或值,可以使用对象的`name`和`value`属性。

print(Day.SUNDAY.name, Day.SUNDAY.value)

检查是否相等

回顾一下,将枚举成员赋值给变量会创建一个对枚举成员对象的引用。因此,要检查变量是否具有特定的枚举成员,我们使用`is`运算符来检查枚举成员和变量是否指向同一个对象。

以下是一个示例:

today = Day.WEDNESDAY

if today is Day.MONDAY:
    print("It's a Monday, :(")

if today is Day.WEDNESDAY:
    print("Happy Wednesday")

或者,你可以使用`==`运算符。在`Enum`类的超类中,`==`运算符是对`is`运算符的封装。这是通过运算符重载来实现的。你可以在关于MagicMethods的文章中了解更多信息。无论如何,以下是使用`==`而不是`is`的例子。

today = Day.WEDNESDAY

if today == Day.MONDAY:
    print("It's a Monday, :(")

if today == Day.WEDNESDAY:
    print("Happy Wednesday")

再次强调,枚举比较是检查对象标识,而不是值。

最后的话

本文介绍了枚举的概念及其用途。我们还介绍了通过子类化`Enum`类以及使用函数式API来创建枚举的不同方法。

此外,我们还介绍了如何使用枚举、访问值以及进行比较。接下来,你可能想阅读我们关于TypeScript枚举的文章。