itertools 循环更快是因为其实现为无状态、惰性迭代器,按需计算且不生成中间列表。例如 product 避免 OOM,islice 正确跳过不缓存,groupby 要求预排序,chain 零拷贝拼接——核心是控制数据流动而非落地。

为什么 itertools 的循环比手写 for 快?
不是因为“底层用 C”这种笼统说法,而是它把常见组合逻辑(如笛卡尔积、分组、无限迭代)做成了无状态、不生成中间列表的惰性迭代器。比如 itertools.product(a, b) 不会先构造出全部元组再返回,而是在每次 next() 时按需计算——内存占用恒定,且避免了 Python 层面的循环开销。
典型反例:[(x, y) for x in a for y in b] 会一次性生成所有组合,当 a 和 b 各有 10⁴ 元素时,产生 1 亿个元组,直接 OOM;而 itertools.product(a, b) 可以逐个处理,配合 break 或条件过滤,早停成本极低。
itertools.islice 截取大迭代器的正确姿势
别用 list(it)[start:end],那会强制展开整个迭代器;也别以为 islice(it, n) 就是“取前 n 个”那么简单——它内部跳过元素靠的是 next() 调用,不缓存、不回退。
- 要跳过前 k 个再取 m 个:用
itertools.islice(it, k, k + m),不是islice(islice(it, k), m)(后者会多走一次 k 步) - 如果源迭代器本身带副作用(比如读文件、调用 API),
islice不会帮你“预热”或“重置”,跳过的元素就彻底丢了 - 和
enumerate()混用时注意索引偏移:enumerate(itertools.islice(it, 100, 200))返回的索引是 0–99,不是 100–199
用 itertools.groupby 前必须排序?
必须。这不是建议,是硬性要求。groupby 只合并相邻相同键的元素,不聚类全局数据。比如对 [3,1,2,1,3] 直接 groupby,会得到 5 组单元素;而先 sorted() 再 groupby 才能得到 {1: [1,1], 2: [2], 3: [3,3]}。
立即学习“Python免费学习笔记(深入)”;
织梦DEDE5凭借其专业的技术、丰富的电子商务经验在第一时刻为此最流行的购物方式推出开源程序。独立编译模板、自由修改、代码简洁,安全高效、数据缓存等技术的应用,使其能在大浏览量的环境下快速稳定运行,切实节约网站成本,提升形象。同行业比较,织梦DEDE5的优势在哪里?整体规划 摒弃开发速度慢,效率低下、冗余严重的框架。投入大量的时间和精力,打造最简洁高效的程序开源程序 我们渴望公平、公正、开放的竞争
常见误用场景:
- 按字符串首字母分组:错写成
groupby(words, key=lambda w: w[0])而忘了sorted(words, key=lambda w: w[0]) - 处理日志行,想按日期分组:如果日志没按时间排序,
groupby会把同一天的日志切成多个碎片 - 性能陷阱:
sorted()是 O(n log n),若只需局部连续分组(如已按时间追加写入的文件),反而该用itertools.groupby原生行为
itertools.chain 和加号 + 列表拼接的区别
itertools.chain(a, b, c) 返回一个迭代器,不复制数据;a + b + c 创建新列表,触发三次内存分配和元素拷贝。当 a/b/c 是大型 range、数据库游标或生成器时,差异立现。
但要注意边界情况:
-
chain无法通过下标访问:chained[5]报TypeError;需要随机访问就得转list,此时优势消失 - 如果其中一个参数是空迭代器(如
iter([])),chain完全忽略它;而[] + [] + [1]仍得[1],语义一致但实现路径不同 - 嵌套结构常用
chain.from_iterable(nested),等价于chain(*nested),但避免了展开大列表的内存峰值
真正难的不是记住函数名,是判断什么时候该让数据“流起来”,什么时候必须“落地成列表”。itertools 的每个函数都在逼你直面这个选择。









