enum 模块:枚举类型

Python enum 模块提供创建枚举类型的功能,提高代码可读性和安全性

分类: stdlib 难度: 初级 更新: 2024-01-15
enum 枚举 常量 类型安全

enum 模块:枚举类型

📝 概述

Python 的enum模块提供了创建枚举类型的功能,这是一种将符号名称绑定到唯一常量值的类。枚举类型可以显著提高代码的可读性、安全性和可维护性,特别适用于处理有限的、预定义的选项集。

🎯 学习目标

  • 理解枚举类型的概念和优势
  • 掌握 Enum 和 IntEnum 的使用方法
  • 学会使用 auto()函数自动赋值
  • 了解枚举成员的比较和别名机制
  • 掌握@unique 装饰器确保值的唯一性

📋 前置知识

  • Python 基础语法
  • 类和对象的概念
  • 装饰器的基本使用

🔍 详细内容

基本概念

枚举是一种数据类型,它包含一组命名的常量。使用枚举的主要优势:

  • 可读性:用有意义的名称代替数字或字符串常量
  • 安全性:限制变量只能取枚举成员的值
  • 可维护性:集中管理常量值,便于修改

核心类和函数

类/函数 说明
Enum 基础枚举类
IntEnum 整数枚举类,支持数值运算
auto() 自动生成唯一值
@unique 装饰器,确保枚举值唯一

枚举成员属性

属性 类型 说明
name str 枚举成员的名称
value Any 枚举成员的值

💡 实际应用

基础用法

from enum import Enum

## 创建基本枚举
class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

## 访问枚举成员
print(Color.RED)        # Color.RED
print(Color.RED.name)   # RED
print(Color.RED.value)  # 1

## 枚举迭代
print("所有颜色:")
for color in Color:
    print(f"{color.name}: {color.value}")

字符串值枚举

from enum import Enum

class Weekday(Enum):
    MONDAY = "Mon"
    TUESDAY = "Tue"
    WEDNESDAY = "Wed"
    THURSDAY = "Thu"
    FRIDAY = "Fri"
    SATURDAY = "Sat"
    SUNDAY = "Sun"

## 使用字符串值
today = Weekday.MONDAY
print(f"今天是: {today.value}")  # 今天是: Mon

IntEnum 的使用

from enum import IntEnum

class Permission(IntEnum):
    READ = 1
    WRITE = 2
    EXECUTE = 4

## IntEnum 支持数值运算
full_permission = Permission.READ | Permission.WRITE | Permission.EXECUTE
print(f"完整权限值: {full_permission}")  # 完整权限值: 7

## 可以与整数比较
print(Permission.READ == 1)  # True
print(Permission.READ < Permission.WRITE)  # True

自动赋值

from enum import Enum, auto

class Shape(Enum):
    CIRCLE = auto()
    SQUARE = auto()
    TRIANGLE = auto()
    RECTANGLE = auto()

## auto()自动生成唯一值
for shape in Shape:
    print(f"{shape.name}: {shape.value}")
## CIRCLE: 1
## SQUARE: 2
## TRIANGLE: 3
## RECTANGLE: 4

唯一性检查

from enum import Enum, unique

@unique
class ErrorCode(Enum):
    SUCCESS = 0
    FILE_NOT_FOUND = 1
    PERMISSION_DENIED = 2
    NETWORK_ERROR = 3

## 如果有重复值,@unique 会抛出 ValueError
print("所有错误码:")
for code in ErrorCode:
    print(f"{code.name}: {code.value}")

枚举别名

from enum import Enum

class State(Enum):
    RUNNING = 1
    ACTIVE = 1      # ACTIVE 是 RUNNING 的别名
    STOPPED = 2
    INACTIVE = 2    # INACTIVE 是 STOPPED 的别名

## 别名指向同一个枚举成员
print(State.RUNNING)    # State.RUNNING
print(State.ACTIVE)     # State.RUNNING
print(State.RUNNING is State.ACTIVE)  # True

## 迭代时只返回主要成员
print("主要状态:")
for state in State:
    print(state.name)
## RUNNING
## STOPPED

枚举比较

from enum import Enum

class Priority(Enum):
    LOW = 1
    MEDIUM = 2
    HIGH = 3

## 枚举成员比较
print(Priority.LOW == Priority.LOW)     # True
print(Priority.LOW is Priority.LOW)     # True
print(Priority.LOW == Priority.HIGH)    # False

## 不能与其他类型直接比较
print(Priority.LOW == 1)                # False

## 但 IntEnum 可以与整数比较
from enum import IntEnum

class IntPriority(IntEnum):
    LOW = 1
    MEDIUM = 2
    HIGH = 3

print(IntPriority.LOW == 1)             # True

实际案例:HTTP 状态码

from enum import IntEnum

class HTTPStatus(IntEnum):
#    # 成功状态码
    OK = 200
    CREATED = 201
    ACCEPTED = 202
    
#    # 重定向状态码
    MOVED_PERMANENTLY = 301
    FOUND = 302
    
#    # 客户端错误
    BAD_REQUEST = 400
    UNAUTHORIZED = 401
    FORBIDDEN = 403
    NOT_FOUND = 404
    
#    # 服务器错误
    INTERNAL_SERVER_ERROR = 500
    BAD_GATEWAY = 502
    SERVICE_UNAVAILABLE = 503

def handle_response(status_code):
    """处理 HTTP 响应状态码"""
    if status_code == HTTPStatus.OK:
        return "请求成功"
    elif status_code == HTTPStatus.NOT_FOUND:
        return "资源未找到"
    elif status_code >= HTTPStatus.INTERNAL_SERVER_ERROR:
        return "服务器错误"
    elif status_code >= HTTPStatus.BAD_REQUEST:
        return "客户端错误"
    else:
        return "其他状态"

## 使用示例
print(handle_response(HTTPStatus.OK))        # 请求成功
print(handle_response(HTTPStatus.NOT_FOUND)) # 资源未找到
print(handle_response(500))                  # 服务器错误

实际案例:交通灯控制系统

from enum import Enum
import time

class TrafficLight(Enum):
    RED = "红灯"
    YELLOW = "黄灯"
    GREEN = "绿灯"
    
    def next_light(self):
        """获取下一个灯的状态"""
        transitions = {
            TrafficLight.RED: TrafficLight.GREEN,
            TrafficLight.GREEN: TrafficLight.YELLOW,
            TrafficLight.YELLOW: TrafficLight.RED
        }
        return transitions[self]
    
    def duration(self):
        """获取当前灯的持续时间(秒)"""
        durations = {
            TrafficLight.RED: 30,
            TrafficLight.YELLOW: 5,
            TrafficLight.GREEN: 25
        }
        return durations[self]

def simulate_traffic_light():
    """模拟交通灯运行"""
    current_light = TrafficLight.RED
    
    for cycle in range(3):  # 运行 3 个周期
        print(f"\n=== 周期 {cycle + 1} ===")
        for _ in range(3):  # 每个周期 3 个灯
            print(f"当前状态: {current_light.value}")
            print(f"持续时间: {current_light.duration()}秒")
            
#            # 模拟等待(实际应用中会真正等待)
#            # time.sleep(current_light.duration())
            
            current_light = current_light.next_light()
            print("-" * 20)

## 运行模拟
simulate_traffic_light()

高级用法:功能枚举

from enum import Enum

class Planet(Enum):
    MERCURY = (3.303e+23, 2.4397e6)
    VENUS   = (4.869e+24, 6.0518e6)
    EARTH   = (5.976e+24, 6.37814e6)
    MARS    = (6.421e+23, 3.3972e6)
    
    def __init__(self, mass, radius):
        self.mass = mass       # 质量 (kg)
        self.radius = radius   # 半径 (m)
    
    @property
    def surface_gravity(self):
        """计算表面重力加速度"""
        G = 6.67300E-11  # 万有引力常数
        return G * self.mass / (self.radius * self.radius)

## 使用功能枚举
earth = Planet.EARTH
print(f"地球质量: {earth.mass:.2e} kg")
print(f"地球半径: {earth.radius:.2e} m")
print(f"地球表面重力: {earth.surface_gravity:.2f} m/s²")

## 比较所有行星的重力
print("\n 各行星表面重力:")
for planet in Planet:
    print(f"{planet.name}: {planet.surface_gravity:.2f} m/s²")

⚠️ 注意事项

  • 枚举成员一旦创建就不可修改
  • 普通 Enum 不能与其他类型进行数值比较,但 IntEnum 可以
  • 使用@unique 装饰器可以防止意外的重复值
  • 枚举成员的值可以是任何类型,但建议保持一致性
  • 别名成员在迭代时不会出现,只有主要成员会被迭代

🔗 相关内容

📚 扩展阅读

🏷️ 标签

enum 枚举 常量 类型安全 代码可读性


最后更新: 2024-01-15
作者: Python 文档团队
版本: 1.0

作者: Python 文档团队

版本: 1.0

讨论与反馈

欢迎在下方留言讨论,分享你的学习心得或提出问题。评论基于GitHub Issues,需要GitHub账号。