Python 推导式与迭代工具
AI 辅助生成本文由 AI 起草并经人工核查,示例均标明软件版本;发现错误请以官方文档为准。
把「新建空列表 → 循环 → append」压缩成一行,代码更短也更贴近意图。这一篇讲推导式和标准库里的迭代工具。
环境准备
示例在 Python 3.13 下验证,itertools 是标准库,无需安装。
列表推导式
numbers = [1, 2, 3, 4, 5]
squares = [n * n for n in numbers] # [1, 4, 9, 16, 25]
evens = [n for n in numbers if n % 2 == 0] # [2, 4]
带条件表达式(三元):
labels = ["偶" if n % 2 == 0 else "奇" for n in numbers]
# ['奇', '偶', '奇', '偶', '奇']
嵌套循环:
pairs = [(x, y) for x in range(3) for y in range(2)]
# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
顺序和手写 for 一致:外层在前。
字典与集合推导式
names = ["python", "go", "rust"]
lengths = {name: len(name) for name in names} # {'python': 6, 'go': 2, 'rust': 4}
# 键值互换
inverted = {v: k for k, v in lengths.items()}
# 过滤字典
adults = {name: age for name, age in ages.items() if age >= 18}
unique_lengths = {len(name) for name in names} # {6, 2, 4}
生成器表达式
把方括号换成圆括号,就是惰性的生成器:不一次性算出全部结果。
total = sum(n * n for n in range(10_000_000)) # 不需要先建一个巨大列表
生成器只能遍历一次,要复用就转成列表或用函数封装。
单参数调用时可以省略一层括号,sum(x for x in xs) 与 sum(gen) 等价。
内置迭代工具
for i, name in enumerate(names, start=1): # 带下标
print(i, name)
for name, score in zip(names, scores): # 并行遍历,以短的为准
print(name, score)
zip 默认会静默截断,长度必须一致时加 strict=True(3.10+):
list(zip(names, scores, strict=True)) # 长度不等抛 ValueError
排序与最值:
sorted(words, key=len) # 按长度升序
sorted(words, key=str.lower) # 忽略大小写
sorted(users, key=lambda u: u.age, reverse=True)
max(words, key=len) # 最长的词
去重保序、反转、连接:
list(dict.fromkeys(items)) # 去重且保持原顺序
list(reversed(items)) # 反向迭代,不复制列表
", ".join(names) # 拼字符串
any() / all() 配合生成器很实用:
any(n > 100 for n in numbers) # 有没有超过 100 的
all(n > 0 for n in numbers) # 是不是全为正
itertools 常用函数
from itertools import chain, islice, count, groupby, combinations
list(chain([1, 2], [3, 4])) # [1, 2, 3, 4],串起多个可迭代对象
list(islice(range(100), 5)) # [0, 1, 2, 3, 4],切片但不建列表
list(islice(count(10, 2), 3)) # [10, 12, 14],无限序列取前 3 个
list(combinations("abc", 2)) # [('a','b'), ('a','c'), ('b','c')]
groupby 把相邻的同键元素分组,必须先按同一键排序:
rows = [("a", 1), ("a", 2), ("b", 3)]
for key, group in groupby(rows, key=lambda r: r[0]):
print(key, list(group))
# a [('a', 1), ('a', 2)]
# b [('b', 3)]
常见错误与注意事项
1. 推导式嵌套过深
两层以上就该换成普通 for 循环,可读性优先。
2. 在推导式里做副作用
[print(n) for n in numbers] # 只为副作用,浪费一个列表
直接写循环。
3. 生成器只能用一次
gen = (n * n for n in numbers)
list(gen) # [1, 4, 9]
list(gen) # [],已耗尽
4. groupby 没排序
未排序时同键元素不相邻,会被分成多组。
5. sorted 与 list.sort 搞混
sorted() 返回新列表;list.sort() 就地排序、返回 None。
小结
- 推导式用于「变换 + 过滤」,字典集合推导式语法一致。
- 数据量大或只遍历一次时用生成器表达式,省内存。
enumerate/zip(strict=True)/sorted(key=...)覆盖大部分循环场景。itertools提供无限序列、切片、分组、组合等工具。