itertools.permutations和combinations更稳,因其底层用C实现,不爆栈、不漏解、不重复生成中间列表;手写递归易在边界条件出错,而itertools行为明确定义:返回迭代器、不预分配内存、不对重复元素去重。

为什么直接用 itertools.permutations 和 itertools.combinations 比手写递归更稳?
因为它们底层用 C 实现,不爆栈、不漏解、不重复生成中间列表。手写递归容易在边界条件(比如空输入、r=0)出错,而 itertools 的行为是明确定义的:返回迭代器,不预分配内存,且对重复元素不做去重——这点必须自己处理。
常见错误现象:list(itertools.permutations([1, 1, 2])) 返回 6 个结果(含重复排列),不是 3 个;itertools.combinations('abc', 4) 直接返回空迭代器,不报错,但新手常误以为“没运行”。
-
permutations(iterable, r=None):若r不填,默认取全部长度;r > len(iterable)时返回空 -
combinations(iterable, r):r必须显式指定,且r 或过大都安静返回空 - 所有函数返回的是迭代器,要转
list才能看全——但大数据量下别这么干
怎么让 itertools.product 替代多层 for 循环?
当你要做笛卡尔积(比如遍历所有参数组合、生成测试用例),itertools.product 是最直白的替代方案。它比嵌套 for 更易读,也支持 repeat 参数快速实现自乘。
使用场景:超参网格搜索、路径拼接、枚举状态机所有输入组合。
立即学习“Python免费学习笔记(深入)”;
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
-
product(A, B)等价于[(a,b) for a in A for b in B] -
product(range(2), repeat=3)生成所有 3 位二进制元组:(0,0,0),(0,0,1), ...,(1,1,1) - 注意:
product不会自动 flatten,如果需要一维结果,得套一层chain.from_iterable或用生成器表达式
如何避免 itertools.chain 和 itertools.chain.from_iterable 混用出错?
这两个函数看起来像,但输入结构完全不同:chain(a, b, c) 接收多个可迭代对象;chain.from_iterable(nested) 接收一个“可迭代对象的可迭代对象”,比如列表套列表。
典型错误:把 [[1,2], [3,4]] 传给 chain,结果是 [ [1,2], [3,4] ](原样输出),而不是 [1,2,3,4];反过来,把 [1,2], [3,4] 传给 from_iterable 会报 TypeError。
- 要展平一层嵌套,优先用
chain.from_iterable(nested_list) - 要拼接几个独立序列(如
range(3),'ab',[None]),用chain(range(3), 'ab', [None]) - 两者都不消耗源数据,但多次遍历需重新调用——这不是 bug,是设计如此
为什么 itertools.groupby 必须先排序?
groupby 只对连续相同键的元素分组,不是按值全局聚合。这是它和 dict 或 pandas.groupby 最关键的区别,也是最容易踩的坑。
错误现象:groupby([1,2,1,2], key=lambda x:x) 会产出 4 组(每项各一组),而不是 2 组。
- 正确用法:先
sorted(data, key=key_func),再groupby(..., key=key_func) - key 函数返回值必须可哈希;若要用复杂对象作 key,确保其
__hash__和__eq__一致 - 返回的 group 是迭代器,只可遍历一次——想多次用就得转成
list或tuple
真正难的不是语法,是记住哪些函数返回惰性迭代器、哪些要求输入有序、哪些对重复敏感——这些细节不翻文档就容易掉进静默陷阱里。

















