Skip to content

14.1 枚举类型基础使用

在 Python 中,枚举(Enum)是一种特殊的类,用于定义一组命名的常量。它让代码更具可读性和可维护性,避免了魔法数字或字符串的滥用。比如,我们想表示一周的七天,用数字 0-6 可能不够直观,而用枚举就可以清晰地表达。

Python 提供了 enum 模块来支持枚举类型。通过继承 Enum 类,我们可以轻松创建自己的枚举。

下面是一个简单的例子:

python
# 导入 Enum 类
from enum import Enum

# 定义一个 Weekday 枚举类
class Weekday(Enum):
    MONDAY = 1      # 周一对应值 1
    TUESDAY = 2     # 周二对应值 2
    WEDNESDAY = 3   # 周三对应值 3
    THURSDAY = 4    # 周四对应值 4
    FRIDAY = 5      # 周五对应值 5
    SATURDAY = 6    # 周六对应值 6
    SUNDAY = 7      # 周日对应值 7

# 使用枚举成员
today = Weekday.MONDAY  # 获取周一的枚举成员
print(today)            # 输出: Weekday.MONDAY
print(today.name)       # 输出: MONDAY (获取名称)
print(today.value)      # 输出: 1 (获取值)

# 通过值访问枚举成员
another_day = Weekday(3)
print(another_day)      # 输出: Weekday.WEDNESDAY

# 通过名称访问枚举成员
yet_another_day = Weekday['FRIDAY']
print(yet_another_day)  # 输出: Weekday.FRIDAY

枚举类型是不可变的,一旦定义就不能修改其成员。此外,枚举成员之间可以进行比较,但不能与其他类型直接比较(除非值相同且类型兼容)。

注意事项:

  • 枚举成员的值可以是任意类型(整数、字符串等),但通常使用整数。
  • 枚举成员是单例的,即 Weekday.MONDAY is Weekday.MONDAYTrue
  • 枚举主要用于提高代码可读性,而不是性能优化。

这一节介绍了如何使用 Python 的 enum 模块创建和使用枚举类型,让代码更清晰易懂。

14.2 命名元组创建与访问

命名元组(Named Tuple)是 collections 模块中的一个工具,它扩展了普通元组的功能,允许通过名称而不是索引来访问元素。这使得代码更加自解释,尤其适用于表示简单对象(如坐标、数据库记录等)。

要创建命名元组,我们需要使用 collections.namedtuple 工厂函数。

python
# 导入 namedtuple
from collections import namedtuple

# 创建一个 Point 命名元组,包含 x 和 y 两个字段
Point = namedtuple('Point', ['x', 'y'])

# 创建 Point 实例
p = Point(10, 20)

# 通过索引访问(兼容普通元组)
print(p[0])   # 输出: 10
print(p[1])   # 输出: 20

# 通过字段名访问(更清晰)
print(p.x)    # 输出: 10
print(p.y)    # 输出: 20

# 命名元组是不可变的,尝试修改会报错
# p.x = 30  # 这会引发 AttributeError

# 使用 _replace 方法创建新实例(因为不可变)
p2 = p._replace(x=30)
print(p2)     # 输出: Point(x=30, y=20)

命名元组还提供了一些有用的内置方法,如 _asdict() 可以将命名元组转换为字典。

python
# 转换为字典
point_dict = p._asdict()
print(point_dict)  # 输出: {'x': 10, 'y': 20}

注意事项:

  • 命名元组是轻量级的,比普通类更节省内存。
  • 字段名不能是 Python 关键字,也不能以下划线开头(除非是特殊方法)。
  • 命名元组适用于表示不可变的简单数据结构。

这一节讲解了如何使用命名元组来创建具有字段名的元组,提升代码的可读性和维护性。

14.3 数据类简化类定义

Python 3.7 引入了 dataclasses 模块,它可以通过装饰器自动生成常见的特殊方法(如 __init____repr____eq__ 等),从而简化类的定义。这对于主要用来存储数据的类特别有用。

使用 @dataclass 装饰器,我们可以避免手动编写冗长的初始化代码。

python
# 导入 dataclass 装饰器
from dataclasses import dataclass

# 定义一个 Person 数据类
@dataclass
class Person:
    name: str      # 姓名,类型注解为 str
    age: int       # 年龄,类型注解为 int
    email: str = ""  # 邮箱,有默认值

# 创建 Person 实例
person = Person("Alice", 30, "alice@example.com")

# 自动生成 __repr__
print(person)  # 输出: Person(name='Alice', age=30, email='alice@example.com')

# 自动生成 __eq__
another_person = Person("Alice", 30, "alice@example.com")
print(person == another_person)  # 输出: True

# 修改属性(数据类默认是可变的)
person.age = 31
print(person.age)  # 输出: 31

如果希望数据类是不可变的,可以设置 frozen=True

python
@dataclass(frozen=True)
class ImmutablePerson:
    name: str
    age: int

# 创建实例
ip = ImmutablePerson("Bob", 25)

# 尝试修改会报错
# ip.age = 26  # 这会引发 dataclasses.FrozenInstanceError

注意事项:

  • 数据类依赖于类型注解,字段必须有类型提示。
  • 默认情况下,数据类是可变的;若需不可变,需设置 frozen=True
  • 数据类适用于主要存储数据、行为较少的类。

这一节展示了如何使用 dataclasses 模块简化类的定义,减少样板代码。

14.4 常用内置函数回顾

Python 提供了许多内置函数,它们无需导入即可直接使用。这些函数覆盖了类型转换、迭代、数学运算等多个方面。这里回顾几个常用且实用的内置函数。

功能名称调用方法具体功能、注意事项
类型转换int(x), str(x), list(x)将 x 转换为指定类型;注意转换失败会抛出异常
最大/最小值max(iterable), min(iterable)返回可迭代对象中的最大/最小值;要求元素可比较
枚举迭代enumerate(iterable)返回 (index, value) 对,便于同时获取索引和值
过滤元素filter(function, iterable)返回满足 function 条件的元素迭代器;function 返回布尔值
映射操作map(function, iterable)对 iterable 中每个元素应用 function,返回结果迭代器

下面是一个综合示例:

python
# 示例:处理一个数字列表
numbers = [1, 2, 3, 4, 5]

# 使用 map 将每个数字平方
squared = list(map(lambda x: x ** 2, numbers))
print(squared)  # 输出: [1, 4, 9, 16, 25]

# 使用 filter 筛选出偶数
evens = list(filter(lambda x: x % 2 == 0, squared))
print(evens)    # 输出: [4, 16]

# 使用 enumerate 打印索引和值
for index, value in enumerate(evens):
    print(f"Index {index}: {value}")
# 输出:
# Index 0: 4
# Index 1: 16

# 使用 max 和 min
print(max(evens))  # 输出: 16
print(min(evens))  # 输出: 4

# 类型转换示例
num_str = "123"
num_int = int(num_str)  # 转换为整数
print(num_int + 1)      # 输出: 124

注意事项:

  • mapfilter 返回的是迭代器,需要转换为列表才能多次使用。
  • 内置函数通常效率较高,优先考虑使用而非手动实现。
  • 类型转换时要注意输入的有效性,避免 ValueError

这一节回顾了几个常用的内置函数,帮助我们更高效地处理数据。

14.5 日志记录 logging

logging 模块是 Python 标准库中用于记录日志的工具。相比简单的 printlogging 可以提供更结构化的日志输出,支持不同的日志级别,并且可以方便地将日志输出到文件、控制台或其他地方。

python
import logging

# 配置日志级别和格式
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

logging.debug("调试信息")
logging.info("一般信息")
logging.warning("警告信息")
logging.error("错误信息")

常用日志级别(从低到高):

  • DEBUG: 调试信息,最详细的日志
  • INFO: 一般信息,确认程序按预期运行
  • WARNING: 警告信息,表示发生了意外情况
  • ERROR: 错误信息,表示程序出现了问题
  • CRITICAL: 严重错误,表示程序可能无法继续运行

建议

在实际项目中,使用 logging 替代 print 进行调试和运维监控,这是一种良好的工程实践。

14.6 命令行参数解析 argparse

argparse 模块用于解析命令行参数,可以轻松地为脚本添加命令行接口和帮助文档。

python
import argparse

parser = argparse.ArgumentParser(description="示例脚本")
parser.add_argument('name', help='你的名字')
parser.add_argument('-a', '--age', type=int, default=18, help='年龄')
args = parser.parse_args()

print(f"你好 {args.name},你的年龄是 {args.age}")

使用方法:

bash
python script.py 张三 -a 25
# 输出: 你好 张三,你的年龄是 25

python script.py --help
# 显示帮助信息

通过 argparse,可以轻松地为脚本添加命令行参数和帮助文档,使脚本更加易用和专业。

14.7 读取环境变量 os.environ

在开发中,我们经常需要从环境变量中读取配置信息,特别是敏感信息(如数据库密码、API密钥等)。os.environ 提供了访问环境变量的方法。

python
import os

# 读取环境变量
db_host = os.environ.get('DB_HOST', 'localhost')
db_port = os.environ.get('DB_PORT', '5432')
print(f"Database: {db_host}:{db_port}")

设置环境变量(在不同系统中):

  • Windows (PowerShell):

    powershell
    $env:DB_HOST = "127.0.0.1"
    $env:DB_PORT = "3306"
  • Linux/macOS:

    bash
    export DB_HOST="127.0.0.1"
    export DB_PORT="3306"

最佳实践

敏感信息(如数据库配置、API密钥)常通过环境变量传入,这是一种良好的工程实践,可以避免将敏感信息硬编码在代码中或提交到版本控制系统。