人人都会AI编程

18.1 itertools:迭代器工具集,高效生成与组合序列

更新时间:2026-07-12

在处理列表、数据集或任何序列时,我们常常需要生成排列组合、过滤数据、分组聚合等操作。用普通循环写这些逻辑不仅代码冗长,还容易导致内存浪费(比如生成巨大的中间列表)。itertools 是 Python 标准库中专为高效迭代设计的模块,它提供了一套构建块(building blocks),让你能用声明式、内存友好的方式处理序列。

核心思想:迭代器即“惰性生产线”

itertools 里的函数几乎都返回迭代器,而不是一次性生成整个列表。这意味着数据是按需产出的——只有当你真正遍历时,元素才会被计算出来。这对处理大数据流或无限序列尤其重要,因为你不会因为内存不足而崩溃。

常用函数分类速览

为了方便记忆和选用,可以把 itertools 的函数分成三类:无限迭代器有限迭代器(终止于最短输入)组合迭代器

1. 无限迭代器(需配合 breakislice 使用)
  • count(start, step):从 start 开始,步长为 step 的无限等差数列。模拟枚举索引或计数器。
  • cycle(iterable):无限循环一个可迭代对象中的元素,周而复始。
  • repeat(elem, n):重复一个元素,可指定次数;若省略 n 则无限重复。

示例:生成流水号 A001, A002, A003 ... 可以用 (f'A{i:03d}' for i in count(1))

2. 有限迭代器(终止于最短输入序列)
  • accumulate(iterable, func):累加(或自定义累积运算)。默认是求和,也可以传入 operator.mul 做累乘等。
  • *chain(iterables) / chain.from_iterable()**:把多个可迭代对象“串联”成一个,像拼接序列一样遍历。
  • compress(data, selectors):根据 selectors 中对应位置的布尔值过滤 data,为 True 则保留。
  • dropwhile(predicate, iterable) / takewhile(predicate, iterable):前置条件丢弃 / 保留,直到条件不满足为止。
  • filterfalse(predicate, iterable):与 filter 相反,保留使 predicateFalse 的元素。
  • groupby(iterable, key):按连续相同的键分组(注意:需要先排序才能全局分组)。
  • islice(iterable, start, stop, step):切片迭代器,返回一个迭代器的切片,类似列表切片但惰性。
  • *zip_longest(iterables, fillvalue)**:类似 zip,但以最长输入为准,缺失部分用 fillvalue 填充。
3. 组合迭代器(排列组合神器)
  • *product(iterables, repeat)**:笛卡尔积(嵌套循环的等价物)。
  • permutations(iterable, r):长度为 r 的排列(顺序有关)。
  • combinations(iterable, r):长度为 r 的组合(顺序无关,不重复)。
  • combinations_with_replacement(iterable, r):允许元素重复的组合。

实际开发中的典型场景

场景一:数据批处理分页
假设从数据库或 API 拉取大量 ID 列表,每次处理 100 条。使用 islice 可以优雅地切片迭代器,而不必一次性加载所有数据到内存。

from itertools import islice

def batch(iterable, size):
    it = iter(iterable)
    while True:
        batch = list(islice(it, size))
        if not batch:
            break
        yield batch

for chunk in batch(range(1000), 100):
    # 处理每个 chunk(100条)
    print(len(chunk))

场景二:生成多条件组合测试用例
接口测试时,你可能需要覆盖多个参数的所有取值组合,用 product 一键生成。

from itertools import product

methods = ['GET', 'POST']
versions = ['v1', 'v2']
envs = ['dev', 'staging', 'prod']

for combo in product(methods, versions, envs):
    print(combo)   # ('GET', 'v1', 'dev') ...

场景三:相邻元素分组(如按日期合并日志)
如果日志文件已经按时间排序,用 groupby 可以轻松把同一天的数据放到一起。

from itertools import groupby
logs = [
    ('2025-01-01', 'login'),
    ('2025-01-01', 'view_page'),
    ('2025-01-02', 'logout')
]

for date, entries in groupby(logs, key=lambda x: x[0]):
    print(f"{date}: {list(entries)}")
# 2025-01-01: [('2025-01-01', 'login'), ('2025-01-01', 'view_page')]
# 2025-01-02: [('2025-01-02', 'logout')]

场景四:避免多层嵌套循环
要遍历多个列表的所有组合,传统写法是嵌套 for,可读性差且层级深。product 让你的意图一目了然。

# 传统
for x in range(3):
    for y in range(2):
        print(x, y)

# 使用 product
from itertools import product
for x, y in product(range(3), range(2)):
    print(x, y)

性能与内存优势

因为所有函数都返回迭代器,它们可以连接成流水线(pipeline)处理大数据而不产生中间列表。例如:

from itertools import islice, filterfalse
# 从某个无限流或大文件中取前10个非空白行
lines = filterfalse(str.isspace, some_huge_file)
first_10 = islice(lines, 10)

全程没有创建一个巨大的临时集合,内存占用极低。这使得 itertools 成为数据管道、流式处理和算法实现中对“可迭代对象”进行变换的标准工具。

什么时候不用 itertools?

如果数据量很小,用简单的列表推导式或生成器表达式就够,不必强行使用 itertools 增加复杂度。但在处理未知大小或极大的序列、需要组合数学操作、拼接多个迭代器时,它就是标准库中最直接、最高效的选择。

掌握 itertools 后,搭配 functools 和生成器,你可以写出简洁、高效、可读的 Python 数据流代码。这正是在数据处理和算法面试中体现 Python 功力的利器。