Python 标准库
Python 标准库提供了丰富的模块和功能,可以满足大多数开发需求。本章将介绍最常用的标准库模块。
概述
Python 标准库是 Python 安装时自带的模块集合,包含:
- 内置函数:如
print()、len()、range()等 - 内置类型:如
list、dict、str等 - 标准模块:如
os、sys、json、datetime等
使用标准库的优势:
- 无需安装:Python 自带,无需额外安装
- 稳定可靠:经过广泛测试和验证
- 跨平台:支持多种操作系统
- 文档完善:官方提供详细文档
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 类型的对应关系:
| JSON | Python |
|---|---|
| object | dict |
| array | list |
| string | str |
| number (int) | int |
| number (real) | float |
| true | True |
| false | False |
| null | None |
文件操作
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类结合了date和time,表示完整的日期时间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 |
| %H | 24小时制小时 | 14 |
| %I | 12小时制小时 | 02 |
| %M | 分钟 | 30 |
| %S | 秒 | 25 |
| %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()只从字符串开头匹配,开头不匹配则返回 Nonesearch()扫描整个字符串寻找第一个匹配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
解释:这三个函数生成无限迭代器,必须配合 break 或 islice 使用,否则会无限循环。
排列组合
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只对相邻的相同元素分组,因此需要先排序takewhile和dropwhile是互补的操作
链式操作
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 标准库中常用的模块:
- os - 操作系统接口,环境变量、文件操作
- sys - 系统参数,命令行参数、模块路径
- json - JSON 编码和解码
- datetime - 日期时间处理
- re - 正则表达式
- math - 数学函数
- random - 随机数生成
- collections - 特殊容器类型
- itertools - 高效迭代器工具
- functools - 高阶函数和工具
- pathlib - 面向对象的路径操作
- typing - 类型注解
这些模块是 Python 开发中不可或缺的工具,熟练掌握它们可以大大提高开发效率。
练习
- 使用
os模块编写一个脚本,列出指定目录下所有文件的大小 - 使用
json模块实现配置文件的读写 - 使用
datetime模块计算从今天到你的生日还有多少天 - 使用
re模块验证邮箱地址格式 - 使用
collections.Counter统计一篇文章中单词出现频率 - 使用
itertools.combinations生成彩票号码组合 - 使用
functools.lru_cache优化递归函数性能 - 使用
pathlib模块编写一个文件搜索工具