跳到主要内容

Python 标准库

Python 标准库提供了丰富的模块和功能,可以满足大多数开发需求。本章将介绍最常用的标准库模块。

概述

Python 标准库是 Python 安装时自带的模块集合,包含:

  • 内置函数:如 print()len()range()
  • 内置类型:如 listdictstr
  • 标准模块:如 ossysjsondatetime

使用标准库的优势:

  1. 无需安装:Python 自带,无需额外安装
  2. 稳定可靠:经过广泛测试和验证
  3. 跨平台:支持多种操作系统
  4. 文档完善:官方提供详细文档

os 模块 - 操作系统接口

os 模块提供了与操作系统交互的便携式方式。

环境变量

import os

# 获取环境变量
home = os.environ.get('HOME') # 获取 HOME 环境变量
path = os.environ.get('PATH', '') # 获取 PATH,不存在则返回空字符串

# 设置环境变量
os.environ['MY_VAR'] = 'my_value'

# 删除环境变量
del os.environ['MY_VAR']

# 获取所有环境变量
for key, value in os.environ.items():
print(f"{key}={value}")

解释os.environ 是一个类似字典的对象,用于访问和修改环境变量。使用 get() 方法可以安全地获取可能不存在的环境变量,避免 KeyError

文件和目录操作

import os

# 当前工作目录
cwd = os.getcwd()
print(f"当前目录: {cwd}")

# 切换目录
os.chdir('/tmp')

# 创建目录
os.mkdir('new_dir') # 创建单层目录
os.makedirs('a/b/c') # 创建多层目录

# 删除目录
os.rmdir('new_dir') # 删除空目录
os.removedirs('a/b/c') # 删除多层空目录

# 列出目录内容
files = os.listdir('.')
for f in files:
print(f)

# 重命名
os.rename('old_name.txt', 'new_name.txt')

# 删除文件
os.remove('file.txt')

解释

  • getcwd() 返回当前工作目录的路径
  • mkdir() 只能创建单层目录,如果父目录不存在会报错
  • makedirs() 可以递归创建多层目录
  • remove() 只能删除文件,不能删除目录

路径操作

import os

# 路径拼接(推荐使用 os.path.join)
path = os.path.join('folder', 'subfolder', 'file.txt')
print(path) # folder/subfolder/file.txt (Unix) 或 folder\subfolder\file.txt (Windows)

# 获取文件名和目录名
filename = os.path.basename('/path/to/file.txt') # file.txt
dirname = os.path.dirname('/path/to/file.txt') # /path/to

# 分割路径和扩展名
name, ext = os.path.splitext('file.txt') # ('file', '.txt')

# 检查路径是否存在
exists = os.path.exists('/path/to/file') # 是否存在
is_file = os.path.isfile('/path/to/file') # 是否是文件
is_dir = os.path.isdir('/path/to/dir') # 是否是目录

# 获取文件信息
size = os.path.getsize('file.txt') # 文件大小(字节)
mtime = os.path.getmtime('file.txt') # 修改时间(时间戳)

解释

  • 使用 os.path.join() 拼接路径可以自动处理不同操作系统的路径分隔符
  • splitext() 用于分离文件名和扩展名,返回元组
  • exists()isfile()isdir() 用于检查路径状态

执行系统命令

import os

# 方式一:os.system(不推荐,无法获取输出)
result = os.system('ls -l')

# 方式二:os.popen(可获取输出)
with os.popen('ls -l') as f:
output = f.read()
print(output)

# 推荐:使用 subprocess 模块(更灵活、更安全)
import subprocess
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
print(result.stdout)

解释os.system() 只返回命令的退出状态码,无法获取输出。推荐使用 subprocess 模块来执行系统命令,它提供了更强大和灵活的功能。

sys 模块 - 系统参数

sys 模块提供了与 Python 解释器相关的变量和函数。

命令行参数

import sys

# sys.argv 是命令行参数列表
# sys.argv[0] 是脚本名称
# sys.argv[1:] 是脚本的参数

# script.py
print(f"脚本名称: {sys.argv[0]}")
print(f"参数列表: {sys.argv[1:]}")

# 运行: python script.py arg1 arg2 arg3
# 输出:
# 脚本名称: script.py
# 参数列表: ['arg1', 'arg2', 'arg3']

解释sys.argv 是一个列表,包含命令行传入的所有参数。第一个元素 sys.argv[0] 始终是脚本名称,后续元素是传入的参数。

模块搜索路径

import sys

# 模块搜索路径
print("Python 模块搜索路径:")
for path in sys.path:
print(f" {path}")

# 添加自定义搜索路径
sys.path.append('/my/custom/path')

# 查看已导入的模块
print("\n已导入的模块:")
for name in list(sys.modules.keys())[:10]: # 只显示前10个
print(f" {name}")

解释

  • sys.path 是一个列表,包含 Python 解释器搜索模块的路径
  • 可以动态添加路径,但只对当前程序有效
  • sys.modules 是一个字典,包含所有已导入的模块

标准输入输出

import sys

# 标准输出
sys.stdout.write("Hello, World!\n")

# 标准错误输出
sys.stderr.write("这是一个错误消息\n")

# 标准输入
line = sys.stdin.readline()

# 重定向输出
original_stdout = sys.stdout
with open('output.txt', 'w') as f:
sys.stdout = f
print("这会写入文件")
sys.stdout = original_stdout # 恢复

解释

  • sys.stdout 是标准输出流,通常指向终端
  • sys.stderr 是标准错误流,用于输出错误信息
  • sys.stdin 是标准输入流
  • 可以重定向这些流到文件或其他对象

其他常用属性

import sys

# Python 版本信息
print(f"Python 版本: {sys.version}")
print(f"版本信息: {sys.version_info}") # (3, 10, 0, 'final', 0)

# 平台信息
print(f"平台: {sys.platform}") # 'linux', 'win32', 'darwin'

# 递归深度限制
print(f"递归深度限制: {sys.getrecursionlimit()}")
sys.setrecursionlimit(2000) # 设置新的限制

# 程序退出
# sys.exit(0) # 正常退出
# sys.exit(1) # 异常退出

# 最大整数值
print(f"最大整数: {sys.maxsize}")

解释

  • sys.version_info 是一个命名元组,可以方便地比较版本
  • sys.platform 返回操作系统标识符
  • sys.exit() 用于退出程序,参数是退出码

json 模块 - JSON 处理

json 模块用于 JSON 数据的编码和解码。

基本使用

import json

# Python 对象转 JSON 字符串
data = {
"name": "张三",
"age": 25,
"skills": ["Python", "JavaScript"],
"active": True,
"salary": None
}

# dumps() - 转换为 JSON 字符串
json_str = json.dumps(data)
print(json_str)
# {"name": "\u5f20\u4e09", "age": 25, "skills": ["Python", "JavaScript"], "active": true, "salary": null}

# ensure_ascii=False - 保留中文
json_str = json.dumps(data, ensure_ascii=False)
print(json_str)
# {"name": "张三", "age": 25, "skills": ["Python", "JavaScript"], "active": true, "salary": null}

# indent - 格式化输出
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)
# {
# "name": "张三",
# "age": 25,
# ...
# }

解释

  • dumps() 将 Python 对象转换为 JSON 字符串
  • ensure_ascii=False 保留非 ASCII 字符(如中文)
  • indent 参数用于格式化输出,便于阅读

JSON 字符串转 Python 对象

import json

json_str = '{"name": "张三", "age": 25, "skills": ["Python", "JavaScript"]}'

# loads() - JSON 字符串转 Python 对象
data = json.loads(json_str)
print(data)
print(type(data)) # <class 'dict'>
print(data['name']) # 张三

解释loads() 将 JSON 字符串解析为 Python 对象。JSON 类型与 Python 类型的对应关系:

JSONPython
objectdict
arraylist
stringstr
number (int)int
number (real)float
trueTrue
falseFalse
nullNone

文件操作

import json

data = {"name": "张三", "age": 25}

# 写入 JSON 文件
with open('data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)

# 读取 JSON 文件
with open('data.json', 'r', encoding='utf-8') as f:
loaded = json.load(f)
print(loaded)

解释

  • dump() 将 Python 对象写入文件
  • load() 从文件读取并解析 JSON
  • 注意指定文件编码为 UTF-8,以正确处理中文

自定义序列化

import json
from datetime import datetime

# 自定义编码器
class DateTimeEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)

data = {
"name": "张三",
"created_at": datetime.now()
}

# 使用自定义编码器
json_str = json.dumps(data, cls=DateTimeEncoder, ensure_ascii=False)
print(json_str)

# 自定义解码
def decode_datetime(dct):
if 'created_at' in dct:
dct['created_at'] = datetime.fromisoformat(dct['created_at'])
return dct

# 使用 object_hook 解码
loaded = json.loads(json_str, object_hook=decode_datetime)
print(type(loaded['created_at'])) # <class 'datetime.datetime'>

解释

  • 继承 JSONEncoder 类并重写 default() 方法可以自定义序列化逻辑
  • object_hook 参数用于自定义反序列化逻辑
  • 这在处理复杂对象(如日期时间)时非常有用

datetime 模块 - 日期时间

datetime 模块提供了处理日期和时间的类。

date 类

from datetime import date

# 创建日期
d = date(2024, 3, 15) # 2024年3月15日
print(d) # 2024-03-15

# 获取当前日期
today = date.today()
print(f"今天: {today}")

# 获取日期属性
print(f"年: {today.year}")
print(f"月: {today.month}")
print(f"日: {today.day}")

# 星期几(0=周一,6=周日)
print(f"星期: {today.weekday()}") # 0-6

# ISO 星期(1=周一,7=周日)
print(f"ISO星期: {today.isoweekday()}") # 1-7

# 格式化输出
print(today.strftime("%Y年%m月%d日")) # 2024年03月15日

# 从字符串解析
d = date.fromisoformat('2024-03-15')

解释

  • date 类表示日期(年、月、日)
  • weekday() 返回 0-6,0 表示周一
  • isoweekday() 返回 1-7,1 表示周一,更符合 ISO 标准

time 类

from datetime import time

# 创建时间
t = time(14, 30, 25) # 14:30:25
print(t) # 14:30:25

# 带微秒
t = time(14, 30, 25, 500000) # 14:30:25.500000

# 获取属性
print(f"时: {t.hour}")
print(f"分: {t.minute}")
print(f"秒: {t.second}")
print(f"微秒: {t.microsecond}")

# 格式化
print(t.strftime("%H时%M分%S秒"))

解释time 类表示一天中的时间(时、分、秒、微秒),不包含日期信息。

datetime 类

from datetime import datetime

# 创建日期时间
dt = datetime(2024, 3, 15, 14, 30, 25)
print(dt) # 2024-03-15 14:30:25

# 获取当前日期时间
now = datetime.now()
print(f"当前时间: {now}")

# 获取当前 UTC 时间
utc_now = datetime.utcnow() # 已弃用,推荐使用:
from datetime import timezone
utc_now = datetime.now(timezone.utc)

# 从字符串解析
dt = datetime.fromisoformat('2024-03-15T14:30:25')

# 自定义格式解析
dt = datetime.strptime('2024/03/15 14:30', '%Y/%m/%d %H:%M')

# 格式化输出
print(now.strftime("%Y-%m-%d %H:%M:%S"))
print(now.strftime("%Y年%m月%d日 %A")) # 2024年03月15日 Friday

解释

  • datetime 类结合了 datetime,表示完整的日期时间
  • strptime() 用于解析字符串为 datetime 对象
  • strftime() 用于格式化 datetime 对象为字符串

timedelta 类 - 时间差

from datetime import datetime, timedelta

# 创建时间差
delta = timedelta(days=7)
print(delta) # 7 days, 0:00:00

# 时间加减
now = datetime.now()
future = now + timedelta(days=7)
past = now - timedelta(days=7)

print(f"一周后: {future}")
print(f"一周前: {past}")

# 时间差可以包含多个单位
delta = timedelta(
days=2,
hours=3,
minutes=30,
seconds=15
)
print(delta) # 2 days, 3:30:15

# 计算两个时间的差
dt1 = datetime(2024, 3, 15)
dt2 = datetime(2024, 3, 20)
diff = dt2 - dt1
print(f"相差: {diff.days} 天") # 相差: 5 天
print(f"总秒数: {diff.total_seconds()}") # 总秒数: 432000.0

解释

  • timedelta 表示时间间隔或持续时间
  • 可以用于日期时间的加减运算
  • total_seconds() 返回总秒数,方便计算

格式化代码

格式代码含义示例
%Y四位年份2024
%y两位年份24
%m两位月份03
%d两位日期15
%H24小时制小时14
%I12小时制小时02
%M分钟30
%S25
%A星期全名Friday
%a星期简写Fri
%B月份全名March
%b月份简写Mar

re 模块 - 正则表达式

re 模块提供了正则表达式操作。

基本匹配

import re

# match() - 从字符串开头匹配
pattern = r'hello'
text = 'hello world'
match = re.match(pattern, text)
if match:
print(f"匹配到: {match.group()}") # 匹配到: hello

# search() - 搜索整个字符串
text = 'say hello world'
match = re.search(pattern, text)
if match:
print(f"找到: {match.group()}") # 找到: hello

# findall() - 找到所有匹配
text = 'hello world, hello python'
matches = re.findall(pattern, text)
print(matches) # ['hello', 'hello']

# finditer() - 返回迭代器
for match in re.finditer(pattern, text):
print(f"位置 {match.start()}: {match.group()}")

解释

  • match() 只从字符串开头匹配,开头不匹配则返回 None
  • search() 扫描整个字符串寻找第一个匹配
  • findall() 返回所有匹配的列表
  • finditer() 返回迭代器,可以获取匹配位置等信息

特殊字符

import re

# . - 任意单个字符(除换行符)
re.findall(r'a.c', 'abc adc a c') # ['abc', 'adc', 'a c']

# ^ - 字符串开头
re.findall(r'^hello', 'hello world') # ['hello']

# $ - 字符串结尾
re.findall(r'world$', 'hello world') # ['world']

# * - 前面的字符出现 0 次或多次
re.findall(r'ab*c', 'ac abc abbc') # ['ac', 'abc', 'abbc']

# + - 前面的字符出现 1 次或多次
re.findall(r'ab+c', 'ac abc abbc') # ['abc', 'abbc']

# ? - 前面的字符出现 0 次或 1 次
re.findall(r'ab?c', 'ac abc abbc') # ['ac', 'abc']

# {n} - 恰好出现 n 次
re.findall(r'a{3}', 'a aa aaa aaaa') # ['aaa', 'aaa']

# {n,m} - 出现 n 到 m 次
re.findall(r'a{2,3}', 'a aa aaa aaaa') # ['aa', 'aaa', 'aaa']

# [] - 字符集合
re.findall(r'[abc]', 'a b c d e') # ['a', 'b', 'c']

# [^] - 否定字符集合
re.findall(r'[^abc]', 'a b c d e') # [' ', ' ', ' ', 'd', 'e']

# \d - 数字
re.findall(r'\d+', 'abc123def456') # ['123', '456']

# \D - 非数字
re.findall(r'\D+', 'abc123def456') # ['abc', 'def']

# \w - 单词字符(字母、数字、下划线)
re.findall(r'\w+', 'hello_world 123') # ['hello_world', '123']

# \s - 空白字符
re.findall(r'\s+', 'hello world') # [' ']

解释:正则表达式的特殊字符用于定义复杂的匹配模式。建议使用原始字符串(r'')来编写正则表达式,避免转义问题。

分组和替换

import re

# 分组
text = '张三: 13812345678, 李四: 13987654321'
pattern = r'(\w+): (\d+)'
matches = re.findall(pattern, text)
print(matches) # [('张三', '13812345678'), ('李四', '13987654321')]

# 命名分组
pattern = r'(?P<name>\w+): (?P<phone>\d+)'
for match in re.finditer(pattern, text):
print(f"姓名: {match.group('name')}, 电话: {match.group('phone')}")

# 替换
text = 'hello 123 world 456'
result = re.sub(r'\d+', '[数字]', text)
print(result) # hello [数字] world [数字]

# 使用函数替换
def double(match):
return str(int(match.group()) * 2)

result = re.sub(r'\d+', double, text)
print(result) # hello 246 world 912

# 分割
text = 'a1b2c3d4'
parts = re.split(r'\d', text)
print(parts) # ['a', 'b', 'c', 'd', '']

解释

  • 使用 () 创建分组,可以通过 group() 方法获取
  • 命名分组 (?P<name>...) 使代码更易读
  • sub() 用于替换匹配的内容
  • split() 按正则表达式分割字符串

编译正则表达式

import re

# 编译正则表达式(提高性能)
pattern = re.compile(r'\d+')

# 使用编译后的模式
text = 'abc123def456'
print(pattern.findall(text)) # ['123', '456']

# 编译时设置标志
pattern = re.compile(r'hello', re.IGNORECASE) # 忽略大小写
print(pattern.findall('HELLO hello Hello')) # ['HELLO', 'hello', 'Hello']

# 常用标志
# re.IGNORECASE (re.I) - 忽略大小写
# re.MULTILINE (re.M) - 多行模式
# re.DOTALL (re.S) - . 匹配包括换行符
# re.VERBOSE (re.X) - 详细模式,可以添加注释

解释:如果同一个正则表达式需要多次使用,编译后可以提升性能。编译时还可以设置各种标志来改变匹配行为。

math 模块 - 数学函数

math 模块提供了数学函数和常量。

常用常量

import math

print(f"圆周率 π: {math.pi}") # 3.141592653589793
print(f"自然常数 e: {math.e}") # 2.718281828459045
print(f"正无穷: {math.inf}") # inf
print(f"非数字: {math.nan}") # nan

基本函数

import math

# 取整函数
print(math.ceil(3.2)) # 4 - 向上取整
print(math.floor(3.8)) # 3 - 向下取整
print(math.trunc(3.8)) # 3 - 截断小数部分

# 绝对值和符号
print(math.fabs(-5)) # 5.0 - 绝对值(返回浮点数)

# 幂运算和对数
print(math.pow(2, 3)) # 8.0 - 幂运算
print(math.sqrt(16)) # 4.0 - 平方根
print(math.exp(1)) # 2.718... - e 的幂
print(math.log(10)) # 自然对数
print(math.log10(100)) # 2.0 - 以 10 为底的对数
print(math.log2(8)) # 3.0 - 以 2 为底的对数

# 三角函数(参数为弧度)
print(math.sin(math.pi/2)) # 1.0
print(math.cos(0)) # 1.0
print(math.tan(math.pi/4)) # 0.999... ≈ 1

# 角度转换
print(math.degrees(math.pi)) # 180.0 - 弧度转角度
print(math.radians(180)) # 3.14159... - 角度转弧度

# 双曲函数
print(math.sinh(1)) # 双曲正弦
print(math.cosh(1)) # 双曲余弦

解释

  • ceil() 向上取整,floor() 向下取整
  • 三角函数的参数是弧度,不是角度
  • 使用 radians()degrees() 进行角度和弧度的转换

特殊函数

import math

# 阶乘
print(math.factorial(5)) # 120 (5! = 5*4*3*2*1)

# 最大公约数
print(math.gcd(12, 8)) # 4

# 最小公倍数(Python 3.9+)
print(math.lcm(4, 6)) # 12

# 判断函数
print(math.isnan(float('nan'))) # True - 是否为 NaN
print(math.isinf(float('inf'))) # True - 是否为无穷
print(math.isfinite(1.0)) # True - 是否为有限数

# 近似相等比较(处理浮点精度问题)
print(math.isclose(0.1 + 0.2, 0.3)) # True

# 组合和排列(Python 3.8+)
print(math.comb(5, 2)) # 10 - 从 5 个中选 2 个的组合数
print(math.perm(5, 2)) # 20 - 从 5 个中选 2 个的排列数

解释

  • 浮点数比较要使用 isclose() 而不是 ==,因为浮点数存在精度问题
  • comb()perm() 用于计算组合数和排列数

random 模块 - 随机数

random 模块用于生成随机数。

基本随机数

import random

# 设置随机种子(确保可重复性)
random.seed(42)

# 0.0 到 1.0 之间的随机浮点数
print(random.random()) # 0.639426...

# 指定范围内的随机整数(包含两端)
print(random.randint(1, 100)) # 1-100 之间的随机整数

# 指定范围内的随机整数(步长)
print(random.randrange(0, 100, 5)) # 0, 5, 10, ..., 95 中随机选一个

# 指定范围内的随机浮点数
print(random.uniform(1.0, 10.0)) # 1.0-10.0 之间的随机浮点数

序列操作

import random

# 从序列中随机选择
items = ['苹果', '香蕉', '橙子', '葡萄']
print(random.choice(items)) # 随机选一个

# 随机选择多个元素(可重复)
print(random.choices(items, k=3)) # ['橙子', '苹果', '苹果']

# 随机选择多个元素(不重复)
print(random.sample(items, k=2)) # ['香蕉', '葡萄']

# 打乱序列
cards = list(range(1, 53))
random.shuffle(cards)
print(cards[:5]) # 打乱后的前 5 张

解释

  • choices() 可以选择重复元素,sample() 选择不重复元素
  • shuffle() 直接修改原序列,不返回新序列

随机分布

import random

# 正态分布(高斯分布)
values = [random.gauss(mu=0, sigma=1) for _ in range(5)]
print(values)

# 指数分布
value = random.expovariate(lambd=1.0)

# 三角分布
value = random.triangular(low=0, high=1, mode=0.5)

collections 模块 - 容器数据类型

collections 模块提供了特殊的容器数据类型。

Counter - 计数器

from collections import Counter

# 统计元素出现次数
text = "hello world"
counter = Counter(text)
print(counter) # Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})

# 从列表创建
words = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
counter = Counter(words)
print(counter) # Counter({'apple': 3, 'banana': 2, 'orange': 1})

# 常用方法
print(counter.most_common(2)) # [('apple', 3), ('banana', 2)] - 最常见的 2 个
print(counter.elements()) # 迭代器,按计数重复元素
print(list(counter.elements())) # ['apple', 'apple', 'apple', 'banana', 'banana', 'orange']

# 计数运算
c1 = Counter('aab')
c2 = Counter('abb')
print(c1 + c2) # Counter({'b': 3, 'a': 3})
print(c1 - c2) # Counter({'a': 1})

解释Counter 是字典的子类,用于计数。most_common() 返回最常见的元素及其计数。

defaultdict - 默认值字典

from collections import defaultdict

# 普通字典访问不存在的键会报错
d = {}
# d['key'] # KeyError

# defaultdict 为不存在的键提供默认值
d = defaultdict(list) # 默认值是空列表
d['fruits'].append('apple')
d['fruits'].append('banana')
print(d) # {'fruits': ['apple', 'banana']}

# 其他默认值类型
d_int = defaultdict(int) # 默认值 0
d_str = defaultdict(str) # 默认值 ''
d_set = defaultdict(set) # 默认值空集合

# 自定义默认值
d = defaultdict(lambda: 'N/A')
print(d['unknown']) # N/A

解释defaultdict 在访问不存在的键时自动创建默认值,避免了 KeyError,特别适合统计和分组操作。

OrderedDict - 有序字典

from collections import OrderedDict

# 保持插入顺序的字典
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
print(list(od.keys())) # ['a', 'b', 'c']

# 移动到末尾
od.move_to_end('a')
print(list(od.keys())) # ['b', 'c', 'a']

# 弹出元素
print(od.popitem(last=True)) # ('a', 3) - 弹出最后一个
print(od.popitem(last=False)) # ('b', 1) - 弹出第一个

解释:Python 3.7+ 的普通字典已经保持插入顺序,OrderedDict 提供了额外的顺序操作方法。

namedtuple - 命名元组

from collections import namedtuple

# 创建命名元组类
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)

print(p.x, p.y) # 3 4
print(p[0], p[1]) # 3 4 - 仍然可以用索引访问

# 有意义的字段名
Person = namedtuple('Person', 'name age city')
person = Person('张三', 25, '北京')
print(f"{person.name}, {person.age}岁, 来自{person.city}")

# 转换为字典
print(person._asdict()) # {'name': '张三', 'age': 25, 'city': '北京'}

# 替换字段(返回新对象)
new_person = person._replace(age=26)
print(new_person)

解释namedtuple 创建类似元组的对象,但可以通过名称访问字段,代码更易读。

deque - 双端队列

from collections import deque

# 创建双端队列
d = deque([1, 2, 3])

# 两端操作(O(1) 时间复杂度)
d.append(4) # 右端添加
d.appendleft(0) # 左端添加
print(d) # deque([0, 1, 2, 3, 4])

d.pop() # 右端弹出
d.popleft() # 左端弹出
print(d) # deque([1, 2, 3])

# 旋转
d.rotate(1) # 向右旋转 1 位
print(d) # deque([3, 1, 2])
d.rotate(-1) # 向左旋转 1 位

# 固定长度队列(自动丢弃旧元素)
d = deque(maxlen=3)
d.extend([1, 2, 3, 4, 5]) # 只保留最后 3 个
print(d) # deque([3, 4, 5], maxlen=3)

解释deque 在两端添加和删除元素的时间复杂度都是 O(1),而列表在头部操作是 O(n)。适合实现队列和栈。

itertools 模块 - 高效迭代器

itertools 模块提供了一组快速、内存高效的迭代器工具,是 Python 函数式编程的重要组成部分。

无限迭代器

import itertools

# count() - 无限计数
for i in itertools.count(start=10, step=2):
if i > 20:
break
print(i) # 10, 12, 14, 16, 18, 20

# cycle() - 无限循环
colors = ['红', '绿', '蓝']
for i, color in enumerate(itertools.cycle(colors)):
if i >= 7:
break
print(color) # 红, 绿, 蓝, 红, 绿, 蓝, 红

# repeat() - 重复元素
for item in itertools.repeat('Hello', 3):
print(item) # Hello, Hello, Hello

解释:这三个函数生成无限迭代器,必须配合 breakislice 使用,否则会无限循环。

排列组合

import itertools

# permutations() - 排列(考虑顺序)
items = ['A', 'B', 'C']
print(list(itertools.permutations(items, 2)))
# [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]

# combinations() - 组合(不考虑顺序,不重复)
print(list(itertools.combinations(items, 2)))
# [('A', 'B'), ('A', 'C'), ('B', 'C')]

# combinations_with_replacement() - 组合(允许重复)
print(list(itertools.combinations_with_replacement(items, 2)))
# [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C')]

# product() - 笛卡尔积
print(list(itertools.product(['A', 'B'], [1, 2])))
# [('A', 1), ('A', 2), ('B', 1), ('B', 2)]

解释

  • permutations 考虑顺序,(A, B)(B, A) 是不同的排列
  • combinations 不考虑顺序,(A, B)(B, A) 视为相同
  • combinations_with_replacement 允许同一元素重复选择
  • product 计算多个可迭代对象的笛卡尔积

过滤和分组

import itertools

# filterfalse() - 过滤掉满足条件的元素
nums = [1, 2, 3, 4, 5, 6]
evens = list(itertools.filterfalse(lambda x: x % 2, nums))
print(evens) # [2, 4, 6]

# takewhile() - 持续取值直到条件不满足
nums = [1, 2, 3, 10, 4, 5]
result = list(itertools.takewhile(lambda x: x < 5, nums))
print(result) # [1, 2, 3]

# dropwhile() - 跳过直到条件不满足
result = list(itertools.dropwhile(lambda x: x < 5, nums))
print(result) # [10, 4, 5]

# groupby() - 分组(需要先排序)
from operator import itemgetter
students = [
{'name': '张三', 'grade': 'A'},
{'name': '李四', 'grade': 'B'},
{'name': '王五', 'grade': 'A'},
{'name': '赵六', 'grade': 'C'},
]
students.sort(key=itemgetter('grade'))
for grade, group in itertools.groupby(students, key=itemgetter('grade')):
print(f"{grade}: {[s['name'] for s in group]}")
# A: ['张三', '王五']
# B: ['李四']
# C: ['赵六']

解释

  • groupby 只对相邻的相同元素分组,因此需要先排序
  • takewhiledropwhile 是互补的操作

链式操作

import itertools

# chain() - 连接多个可迭代对象
list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
print(list(itertools.chain(list1, list2)))
# [1, 2, 3, 'a', 'b', 'c']

# chain.from_iterable() - 从嵌套结构连接
nested = [[1, 2], [3, 4], [5, 6]]
print(list(itertools.chain.from_iterable(nested)))
# [1, 2, 3, 4, 5, 6]

# islice() - 切片(适用于任何迭代器)
nums = itertools.count(0)
print(list(itertools.islice(nums, 5, 10)))
# [5, 6, 7, 8, 9]

# zip_longest() - 填充不等长的迭代
a = [1, 2, 3]
b = ['a', 'b']
print(list(itertools.zip_longest(a, b, fillvalue=None)))
# [(1, 'a'), (2, 'b'), (3, None)]

解释chain 比使用 + 连接列表更高效,因为它不需要创建新的列表。

functools 模块 - 高阶函数

functools 模块提供了用于操作和扩展函数的高阶函数和工具。

partial - 偏函数

partial 用于固定函数的部分参数,创建一个新函数:

from functools import partial

def power(base, exp):
return base ** exp

# 创建平方函数
square = partial(power, exp=2)
print(square(5)) # 25

# 创建立方函数
cube = partial(power, exp=3)
print(cube(3)) # 27

# 固定第一个参数
def greet(greeting, name):
return f"{greeting}, {name}!"

say_hello = partial(greet, "你好")
print(say_hello("张三")) # 你好, 张三!
print(say_hello("李四")) # 你好, 李四!

解释partial 创建的偏函数会记住固定的参数值,调用时只需提供剩余参数。这在需要多次调用相同函数但某些参数固定时非常有用。

lru_cache - 缓存装饰器

lru_cache 装饰器缓存函数结果,避免重复计算:

from functools import lru_cache
import time

@lru_cache(maxsize=128)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)

# 第一次计算
start = time.time()
print(fibonacci(35)) # 9227465
print(f"耗时: {time.time() - start:.4f}秒")

# 第二次计算(从缓存获取)
start = time.time()
print(fibonacci(35)) # 9227465
print(f"耗时: {time.time() - start:.6f}秒") # 几乎为0

# 查看缓存信息
print(fibonacci.cache_info())
# CacheInfo(hits=1, misses=36, maxsize=128, currsize=36)

# 清除缓存
fibonacci.cache_clear()

解释

  • maxsize 参数设置缓存大小,设为 None 表示无限制
  • 缓存基于函数参数,相同参数直接返回缓存结果
  • 适用于计算密集型或 I/O 密集型的纯函数

wraps - 保留函数元信息

wraps 装饰器用于保留被装饰函数的元信息:

from functools import wraps

def my_decorator(func):
@wraps(func) # 保留原函数的元信息
def wrapper(*args, **kwargs):
"""wrapper 的文档字符串"""
print("函数执行前")
result = func(*args, **kwargs)
print("函数执行后")
return result
return wrapper

@my_decorator
def greet(name):
"""问候函数"""
return f"你好,{name}!"

print(greet("张三"))
# 函数执行前
# 你好,张三!
# 函数执行后

print(greet.__name__) # greet(没有 @wraps 会是 wrapper)
print(greet.__doc__) # 问候函数

解释:使用 @wraps(func) 后,被装饰函数的 __name____doc__ 等属性会被保留。这在调试和文档生成时非常重要。

reduce - 归约函数

reduce 对可迭代对象的元素进行累积操作:

from functools import reduce

# 求和
nums = [1, 2, 3, 4, 5]
total = reduce(lambda x, y: x + y, nums)
print(total) # 15

# 求乘积
product = reduce(lambda x, y: x * y, nums)
print(product) # 120

# 带初始值
total = reduce(lambda x, y: x + y, nums, 100)
print(total) # 115

# 找最大值
max_val = reduce(lambda x, y: x if x > y else y, nums)
print(max_val) # 5

# 列表拼接
lists = [[1, 2], [3, 4], [5, 6]]
merged = reduce(lambda x, y: x + y, lists)
print(merged) # [1, 2, 3, 4, 5, 6]

解释reduce 将序列的前两个元素应用函数,结果再与第三个元素应用函数,以此类推。可以指定初始值作为第一个元素。

total_ordering - 自动生成比较方法

total_ordering 装饰器自动生成所有比较方法,只需定义一个:

from functools import total_ordering

@total_ordering
class Student:
def __init__(self, name, score):
self.name = name
self.score = score

def __eq__(self, other):
return self.score == other.score

def __lt__(self, other):
return self.score < other.score

s1 = Student("张三", 85)
s2 = Student("李四", 90)
s3 = Student("王五", 85)

print(s1 < s2) # True
print(s1 == s3) # True
print(s2 > s1) # True(自动生成)
print(s1 <= s3) # True(自动生成)

解释:只需定义 __eq__ 和一个比较方法(如 __lt__),total_ordering 会自动生成 __le____gt____ge__ 等方法。

singledispatch - 单分派泛型函数

singledispatch 根据第一个参数的类型调用不同的函数实现:

from functools import singledispatch

@singledispatch
def process(value):
raise NotImplementedError(f"不支持的类型: {type(value)}")

@process.register
def _(value: int):
return f"处理整数: {value * 2}"

@process.register
def _(value: str):
return f"处理字符串: {value.upper()}"

@process.register
def _(value: list):
return f"处理列表: {len(value)} 个元素"

print(process(10)) # 处理整数: 20
print(process("hello")) # 处理字符串: HELLO
print(process([1, 2, 3])) # 处理列表: 3 个元素

解释singledispatch 实现了基于类型的函数重载,类似于其他语言的多态。这在处理多种类型输入时非常有用。

pathlib 模块 - 路径操作

pathlib 提供了面向对象的路径操作方式。

基本使用

from pathlib import Path

# 创建路径对象
p = Path('folder/subfolder/file.txt')
print(p) # folder/subfolder/file.txt

# 当前目录
cwd = Path.cwd()
print(f"当前目录: {cwd}")

# 用户主目录
home = Path.home()
print(f"主目录: {home}")

# 路径拼接(使用 / 运算符)
data_dir = Path('data')
file_path = data_dir / 'files' / 'data.txt'
print(file_path) # data/files/data.txt

路径属性

from pathlib import Path

p = Path('/home/user/docs/file.txt')

# 路径各部分
print(f"父目录: {p.parent}") # /home/user/docs
print(f"文件名: {p.name}") # file.txt
print(f"文件名(无扩展名): {p.stem}") # file
print(f"扩展名: {p.suffix}") # .txt

# 多级父目录
print(list(p.parents))
# [PosixPath('/home/user/docs'), PosixPath('/home/user'), PosixPath('/home'), PosixPath('/')]

# 路径部分
print(p.parts) # ('/', 'home', 'user', 'docs', 'file.txt')

文件操作

from pathlib import Path

p = Path('test_dir/test_file.txt')

# 创建目录
p.parent.mkdir(parents=True, exist_ok=True)

# 写入文件
p.write_text('Hello, World!', encoding='utf-8')

# 读取文件
content = p.read_text(encoding='utf-8')
print(content) # Hello, World!

# 检查路径
print(p.exists()) # True - 是否存在
print(p.is_file()) # True - 是否是文件
print(p.is_dir()) # False - 是否是目录

# 遍历目录
data_dir = Path('data')
for file in data_dir.iterdir():
print(file.name)

# 递归查找文件
for py_file in Path('.').rglob('*.py'):
print(py_file)

# 查找特定模式
for txt_file in Path('.').glob('*.txt'):
print(txt_file)

解释pathlib 的路径操作比 os.path 更直观,支持面向对象的方式操作路径。推荐在 Python 3.4+ 中使用 pathlib 替代 os.path

typing 模块 - 类型注解

typing 模块提供了类型注解支持。

基本类型注解

from typing import List, Dict, Tuple, Set, Optional

# 列表类型
names: List[str] = ['张三', '李四']

# 字典类型
scores: Dict[str, int] = {'张三': 90, '李四': 85}

# 元组类型
point: Tuple[int, int, int] = (1, 2, 3)

# 集合类型
unique_nums: Set[int] = {1, 2, 3}

# 可选类型(可能为 None)
def greet(name: Optional[str] = None) -> str:
if name is None:
return "你好,陌生人"
return f"你好,{name}"

函数类型注解

from typing import Callable, Any

# 函数参数和返回值类型
def add(a: int, b: int) -> int:
return a + b

# 可调用对象类型
def apply(func: Callable[[int, int], int], x: int, y: int) -> int:
return func(x, y)

result = apply(add, 3, 5) # 8

# 多种返回类型
from typing import Union

def process(value: Union[int, str]) -> str:
if isinstance(value, int):
return str(value)
return value

泛型和类型变量

from typing import TypeVar, Generic, List

# 类型变量
T = TypeVar('T')

# 泛型类
class Stack(Generic[T]):
def __init__(self) -> None:
self.items: List[T] = []

def push(self, item: T) -> None:
self.items.append(item)

def pop(self) -> T:
return self.items.pop()

# 使用
int_stack: Stack[int] = Stack()
int_stack.push(1)
int_stack.push(2)

小结

本章我们学习了 Python 标准库中常用的模块:

  1. os - 操作系统接口,环境变量、文件操作
  2. sys - 系统参数,命令行参数、模块路径
  3. json - JSON 编码和解码
  4. datetime - 日期时间处理
  5. re - 正则表达式
  6. math - 数学函数
  7. random - 随机数生成
  8. collections - 特殊容器类型
  9. itertools - 高效迭代器工具
  10. functools - 高阶函数和工具
  11. pathlib - 面向对象的路径操作
  12. typing - 类型注解

这些模块是 Python 开发中不可或缺的工具,熟练掌握它们可以大大提高开发效率。

练习

  1. 使用 os 模块编写一个脚本,列出指定目录下所有文件的大小
  2. 使用 json 模块实现配置文件的读写
  3. 使用 datetime 模块计算从今天到你的生日还有多少天
  4. 使用 re 模块验证邮箱地址格式
  5. 使用 collections.Counter 统计一篇文章中单词出现频率
  6. 使用 itertools.combinations 生成彩票号码组合
  7. 使用 functools.lru_cache 优化递归函数性能
  8. 使用 pathlib 模块编写一个文件搜索工具

参考资源