>>>PyPathPython 学习站
首页›进阶篇›kp-038
进阶篇 · Advanced lv.3 进阶 kp-038

itertools 与迭代工具箱

前置知识:kp-012、kp-013

1. 一句话定义

itertools 是构建惰性迭代流水线的乐高积木:无穷生成、切片、分组、排列组合、链式拼接——全部以 C 实现、内存 O(1)、组合近乎无限。

2. 为什么重要

它被称为"最 Python 的模块":把 kp-012/013 的协议变成可组合的函数式工具。数据管道、批处理、去重分组等场景,itertools 一行顶十行循环。

3. 前置知识

kp-012(迭代器协议)、kp-013(生成器)。

4. 核心概念(五组积木)

python
from itertools import (count, cycle, islice, chain, groupby,
                       product, permutations, combinations,
                       accumulate, pairwise)

# ① 无穷生成器(必须配 islice/zip 限长)
count(10, 2)                    # 10, 12, 14, ... 无穷
cycle("AB")                     # A, B, A, B, ... 无穷
list(islice(count(), 5))        # [0, 1, 2, 3, 4]

# ② 拼接与切分
chain([1, 2], [3, 4])           # 1 2 3 4(惰性不复制)
list(pairwise([1, 2, 3, 4]))    # [(1,2), (2,3), (3,4)]

# ③ 排列组合
list(combinations("ABC", 2))    # AB AC BC
list(product([0, 1], repeat=2)) # (0,0) (0,1) (1,0) (1,1)

# ④ 归约与累计
list(accumulate([1, 2, 3, 4]))  # [1, 3, 6, 10](前缀和)

# ⑤ 分组(必须先按同 key 排序!)
rows = sorted(data, key=lambda r: r["dept"])
for dept, grp in groupby(rows, key=lambda r: r["dept"]):
    print(dept, len(list(grp)))

配套伙伴:functools(reduce、partial、lru_cache)、more_itertools(社区增强包:chunked、windowed 等)。

5. 原理与机制

text
流水线组合:每个 itertools 函数都返回新迭代器
  islice(filter(None, chain(sources)), 1000)
  = 建一条管道,数据流过时逐段加工,全程物化不超过 1000 条
与列表版差异:不构造任何中间列表(对比 kp-011 的生成器表达式)

groupby 陷阱的根源:它只在相邻元素上分组——所以"按 key 分组"必须先按 key 排序(或用 more_itertools.groupby_unsorted)。

6. 关键事实(模型/图示)

text
选型:
  有限集合 + 要结果列表 → 推导式(kp-011)
  流式/无穷/超大集合    → itertools 管道
  复杂聚合统计          → 让位 pandas/Polars(kp-041)

7. 直观类比

itertools 像乐高基础件:count 是"永动传送带"、islice 是"截断刀"、groupby 是"分拣机"、chain 是"汇流器"。单件不起眼,但按需拼装就能搭出任意数据流水线——而列表推导式是"预制板",适合标准户型,流水线才适合异形工程。

8. 实例与案例

python
# 分批处理(chunked 的标准库写法)
def batches(it, n):
    it = iter(it)
    while batch := list(islice(it, n)):
        yield batch

# 任意迭代器分页拉取 API
for page in batches(ids, 100):
    call_api(page)

9. 常见误区

  1. groupby 忘排序 —— 只对相邻分组,结果碎片化;先 sorted 再 groupby。
  2. 无限迭代器没有限长 —— list(count()) 直接内存爆炸;无限积木必须配 islice/zip/break。
  3. itertools 结果二次消费 —— 全是迭代器,一次性(kp-012 老问题)。
  4. 为小列表硬上 itertools —— 三元素列表写 combinations 不如显式循环清楚;工具服务可读性。

10. 自测题

  1. list(islice(cycle("AB"), 5)) 输出什么?
  2. groupby 分组错误的两个常见原因?
  3. batches 函数为什么用 while ... islice 而不是 for?
参考答案
  1. ['A', 'B', 'A', 'B', 'A']。
  2. 未按分组键排序;源是已耗尽/共享的迭代器导致分块错乱。
  3. islice 取不足 n 个时 batch 短于 n,循环终止条件靠列表空判断——for 无法直接表达"每次取 n 个"的批次语义。

11. 与其他知识点的关系

  • kp-041 数据科学:数据量到表级后迁移到 pandas/Polars。
  • kp-011 推导式:声明式构建的两条路线。
  • kp-013 生成器:itertools 是生成器思维的函数化封装。

12. 延伸阅读

  • itertools 官方文档(每页末的 recipes 段落是宝藏)
  • more-itertools 文档