14.1 枚举类型基础使用
在 Python 中,枚举(Enum)是一种特殊的类,用于定义一组命名的常量。它让代码更具可读性和可维护性,避免了魔法数字或字符串的滥用。比如,我们想表示一周的七天,用数字 0-6 可能不够直观,而用枚举就可以清晰地表达。
Python 提供了 enum 模块来支持枚举类型。通过继承 Enum 类,我们可以轻松创建自己的枚举。
下面是一个简单的例子:
# 导入 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.MONDAY为True。 - 枚举主要用于提高代码可读性,而不是性能优化。
这一节介绍了如何使用 Python 的 enum 模块创建和使用枚举类型,让代码更清晰易懂。
14.2 命名元组创建与访问
命名元组(Named Tuple)是 collections 模块中的一个工具,它扩展了普通元组的功能,允许通过名称而不是索引来访问元素。这使得代码更加自解释,尤其适用于表示简单对象(如坐标、数据库记录等)。
要创建命名元组,我们需要使用 collections.namedtuple 工厂函数。
# 导入 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() 可以将命名元组转换为字典。
# 转换为字典
point_dict = p._asdict()
print(point_dict) # 输出: {'x': 10, 'y': 20}注意事项:
- 命名元组是轻量级的,比普通类更节省内存。
- 字段名不能是 Python 关键字,也不能以下划线开头(除非是特殊方法)。
- 命名元组适用于表示不可变的简单数据结构。
这一节讲解了如何使用命名元组来创建具有字段名的元组,提升代码的可读性和维护性。
14.3 数据类简化类定义
Python 3.7 引入了 dataclasses 模块,它可以通过装饰器自动生成常见的特殊方法(如 __init__、__repr__、__eq__ 等),从而简化类的定义。这对于主要用来存储数据的类特别有用。
使用 @dataclass 装饰器,我们可以避免手动编写冗长的初始化代码。
# 导入 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:
@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,返回结果迭代器 |
下面是一个综合示例:
# 示例:处理一个数字列表
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注意事项:
map和filter返回的是迭代器,需要转换为列表才能多次使用。- 内置函数通常效率较高,优先考虑使用而非手动实现。
- 类型转换时要注意输入的有效性,避免
ValueError。
这一节回顾了几个常用的内置函数,帮助我们更高效地处理数据。
14.5 日志记录 logging
logging 模块是 Python 标准库中用于记录日志的工具。相比简单的 print,logging 可以提供更结构化的日志输出,支持不同的日志级别,并且可以方便地将日志输出到文件、控制台或其他地方。
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 模块用于解析命令行参数,可以轻松地为脚本添加命令行接口和帮助文档。
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}")使用方法:
python script.py 张三 -a 25
# 输出: 你好 张三,你的年龄是 25
python script.py --help
# 显示帮助信息通过 argparse,可以轻松地为脚本添加命令行参数和帮助文档,使脚本更加易用和专业。
14.7 读取环境变量 os.environ
在开发中,我们经常需要从环境变量中读取配置信息,特别是敏感信息(如数据库密码、API密钥等)。os.environ 提供了访问环境变量的方法。
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:
bashexport DB_HOST="127.0.0.1" export DB_PORT="3306"
最佳实践
敏感信息(如数据库配置、API密钥)常通过环境变量传入,这是一种良好的工程实践,可以避免将敏感信息硬编码在代码中或提交到版本控制系统。