Python 推导式与迭代工具

AI 辅助生成本文由 AI 起草并经人工核查,示例均标明软件版本;发现错误请以官方文档为准。

Python 3.13

把「新建空列表 → 循环 → 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 提供无限序列、切片、分组、组合等工具。

下一步