itertools 和 functools 是 Python 里两个”看起来抽象、实际非常实用”的标准库。前者提供各种迭代器组合器,后者提供函数式编程工具。两者搭配起来,你能用几行代码解决”分组”、”分块”、”缓存”、”偏函数”这些常见问题。这一篇讲清楚它们各自最有用的 15 个 API。
一、itertools:迭代器工具箱
无限迭代器
1 | from itertools import count, cycle, repeat |
停止条件迭代器
1 | from itertools import accumulate, chain, compress, dropwhile, takewhile, islice |
组合迭代器
1 | from itertools import product, permutations, combinations, combinations_with_replacement |
用途:暴力枚举、算法题、生成测试用例。
分组
1 | from itertools import groupby |
注意:groupby 只对相邻的相同 key 分组。要”全局分组”先 sorted:
1 | data.sort(key=lambda x: x[0]) |
打包
1 | from itertools import zip_longest, starmap, tee |
注意:tee 底层会缓存已消费的元素——两个迭代器差距大时内存开销大,慎用。
batched(Python 3.12+)
1 | from itertools import batched |
批量分块神器,3.12 之前要自己写(见 生成器 yield 深入)。
二、functools:函数式工具
partial / partialmethod:偏函数
前面 匿名函数 lambda 与高阶函数 讲过:
1 | from functools import partial |
reduce:累积计算
1 | from functools import reduce |
lru_cache / cache:函数缓存
1 | from functools import lru_cache, cache |
要求:参数必须可哈希(list/dict/set 不行;元组/字符串/整数可以)。
wraps:保留元信息
前面 装饰器入门 讲过——写装饰器必备。
singledispatch:函数重载
Python 没有 Java 那种”同名不同参”重载,但用 singledispatch 可以按第一个参数的类型分派:
1 | from functools import singledispatch |
在类方法里用 singledispatchmethod。
cached_property:类的懒加载属性
1 | from functools import cached_property |
第一次访问计算并存到实例 __dict__ 里,之后走属性查找。
total_ordering:补齐比较方法
1 | from functools import total_ordering |
三、operator 模块
不属于 functools,但配套使用非常多:
1 | from operator import add, sub, mul, itemgetter, attrgetter, methodcaller |
四、一些经典组合
分块(3.12 之前)
1 | from itertools import islice |
找连续差值
1 | from itertools import pairwise # 3.10+ |
展平嵌套一层
1 | from itertools import chain |
每个元素前面加 index
1 | list(enumerate("abc")) # 内置就行 |
五、一个完整例子:拼接多个 CSV
1 | # combine.py |
这个例子的关键:chain.from_iterable(generator) 让我们一行行拼接,不用把全部数据读进内存。100GB 数据也能跑。
六、性能提示
itertools都是惰性的——不消费不计算;- 大部分是 C 实现,比手写 Python 循环快;
functools.lru_cache对递归 / 幂等的重计算是”免费加速”;operator.itemgetter/attrgetter比 lambda 快 20-50%。
七、常见陷阱
groupby只按连续分组:忘了 sort 会漏。tee内存:两个迭代器差距大时缓存变大。lru_cache参数不可哈希:TypeError。用 tuple 化,或改用别的缓存。reduce空序列没初始值:TypeError。永远提供 initial 或保证非空。chain(a, b)vschain.from_iterable([a, b]):一个直接传多个,一个传”一个装着可迭代对象的可迭代对象”。permutations数量爆炸:10 个元素的全排列有 362 万种,别乱调。
八、小结与延伸阅读
- itertools:无限迭代(count/cycle/repeat)、组合(product/permutations/combinations)、分组(groupby)、切片(islice)、拼接(chain);
- functools:
partial/reduce/lru_cache/cached_property/singledispatch/total_ordering/wraps; - 配 operator:
itemgetter/attrgetter加速排序; - 处理大数据、组合数学、缓存、装饰器都能派上用场。
延伸阅读:
- itertools:https://docs.python.org/zh-cn/3/library/itertools.html
- functools:https://docs.python.org/zh-cn/3/library/functools.html
- operator:https://docs.python.org/zh-cn/3/library/operator.html
下一篇 日志模块 logging 实战 我们讲怎么写规范的日志。