itertools.product 用于笛卡尔积,需解包传参;groupby 前必须排序;chain 易误展开字符串;islice 是截断无限迭代器的唯一安全方式。

用 itertools.product 替代多层嵌套 for 循环
当你要遍历多个可迭代对象的笛卡尔积(比如参数组合、测试用例生成),手写 3 层以上 for 循环不仅难读,还容易漏掉某一层的 break 或 continue 逻辑。直接用 itertools.product 更安全、更扁平。
常见错误是误传单个列表(如 product([[1,2], [3,4]])),结果只展开一层;正确做法是解包:product([1,2], [3,4]) 或 product(*list_of_lists)。
- 参数顺序即循环嵌套顺序:
product(A, B, C)等价于for a in A: for b in B: for c in C: - 加
repeat=2可简化product(A, A)→product(A, repeat=2) - 返回的是迭代器,不占内存;但若需多次遍历,得转成
list或重新调用
用 itertools.groupby 前必须先排序
groupby 不是 SQL 的 GROUP BY,它只对相邻相同元素分组。如果数据没排好序,同一键值分散在不同位置,就会被拆成多个组——这是最常踩的坑。
典型场景:按用户 ID 聚合日志行、统计连续重复状态。别指望它自动全局聚合。
立即学习“Python免费学习笔记(深入)”;
- 必须先按分组字段排序,例如:
sorted(data, key=lambda x: x['user_id']) -
groupby返回的是(key, group_iterator)对,group_iterator只能遍历一次 - 若要保留原始顺序且按字段聚类,改用
defaultdict(list)更直白
避免 itertools.chain 意外展开字符串
把多个列表拼成一个迭代器时,chain(a, b, c) 很方便;但如果误把字符串当可迭代对象传进去(如 chain([1,2], "ab")),它会把字符串当作字符序列展开成 1, 2, 'a', 'b',而不是你想要的 [1,2,"ab"]。
这在动态拼接混合类型数据(比如配置项 + 用户输入)时特别隐蔽。
- 检查每个参数是否为“预期的容器”,必要时用
isinstance(x, (list, tuple, range))过滤 - 不确定类型时,用
chain.from_iterable([[1,2], ["ab"]])更可控 -
chain本身不递归,不会处理嵌套列表;需要递归展开请用more-itertools.collapse或手写生成器
itertools.islice 是唯一安全截断无限迭代器的方式
对 count()、cycle() 这类无限迭代器,不能用切片语法(it[10:20] 报错),也不能用 list(it)[:10] —— 那会先把整个无限流转成 list,直接卡死。
islice 是惰性的,只取所需项,且支持类似切片的参数(start, stop, step)。
-
islice(it, 100)等价于取前 100 项;islice(it, 10, 20)跳过前 10 项,再取 10 项 -
islice会消耗原迭代器;用完后原迭代器已前进到对应位置,不可重用 - 不要用
islice(it, None, n)代替itertools.takewhile;前者靠数量,后者靠条件
itertools 改用普通 for 或 dict。尤其在调试时看到空的 groupby 结果或意外的字符串展开,十有八九是忘了排序或类型校验。


















