itertools —— Python 最强迭代器工具箱实战 1. 知识点简介itertools是 Python 标准库中最被低估的模块之一。它提供了一组高效、内存友好的迭代器工具让你用声明式的组合替代手写循环。核心设计哲学延迟计算、流式处理、组合复用。一句话总结itertools在手循环代码再也不用从头搓。2. 三大基石无限迭代器2.1count(start0, step1)—— 等差数列from itertools import count # 从 10 开始步长 2 for i in count(10, 2): if i 20: break print(i, end ) # 10 12 14 16 18 20实战搭配zip做自动编号from itertools import count fruits [apple, banana, cherry] for idx, fruit in zip(count(1), fruits): print(f{idx}. {fruit}) # 1. apple # 2. banana # 3. cherry比enumerate(fruits, start1)的好处是count是迭代器适合更复杂的 chaining 场景。2.2cycle(iterable)—— 无限循环from itertools import cycle import time status_indicators cycle([⏳, , ⚙️, ]) for i, icon in enumerate(cycle(status_indicators)): if i 20: break print(f\r{icon} 处理中..., end) time.sleep(0.2)实战轮询分配任务from itertools import cycle backends cycle([server-a, server-b, server-c]) def get_next_backend(): return next(backends) for _ in range(5): print(get_next_backend()) # server-a, server-b, server-c, server-a, server-b2.3repeat(object, timesNone)—— 重复from itertools import repeat # 重复 5 次 for _ in repeat(doing work, 5): print(⚡, end ) # ⚡ ⚡ ⚡ ⚡ ⚡ # 搭配 map 初始化 list(map(pow, range(5), repeat(3))) # [0, 1, 8, 27, 64] ← 0³, 1³, 2³, 3³, 4³3. 数据处理五虎将3.1chain(*iterables)—— 扁平拼接多个可迭代对象from itertools import chain # 代替 a b不用创建中间列表 a [1, 2, 3] b [4, 5, 6] c [x, y] for item in chain(a, b, c): print(item, end ) # 1 2 3 4 5 6 x y # 展平嵌套列表一层 nested [[1, 2], [3, 4], [5]] flattened list(chain.from_iterable(nested)) # [1, 2, 3, 4, 5]chainvs会创建新列表chain是迭代器O(1) 空间。3.2compress(data, selectors)—— 按布尔掩码过滤from itertools import compress data [正常, 异常, 正常, 严重, 正常] mask [True, False, True, True, False] filtered list(compress(data, mask)) # [正常, 正常, 严重] # 实战按条件筛选 scores [88, 45, 92, 67, 73] passing [s 60 for s in scores] passing_scores list(compress(scores, passing)) # [88, 92, 67, 73]3.3dropwhile/takewhile—— 条件式截取from itertools import dropwhile, takewhile data [1, 2, 3, 4, 5, 1, 2, 3] # 跳过开头 3 的元素遇到 3 才开始保留 list(dropwhile(lambda x: x 3, data)) # [4, 5, 1, 2, 3] # 保留开头 3 的元素遇到 3 就停止 list(takewhile(lambda x: x 3, data)) # [1, 2, 3]实战跳过日志文件头部注释# 假设日志内容 lines [# 开始时间: 2026-06-18, # 版本: 2.0, , data1, data2] from itertools import dropwhile data_lines list(dropwhile(lambda l: l.startswith(#) or l , lines)) # [data1, data2]3.4filterfalse(predicate, iterable)—— 反过滤from itertools import filterfalse nums [1, 2, 3, 4, 5, 6] # 选出「不是偶数」的数 → 奇数 list(filterfalse(lambda x: x % 2 0, nums)) # [1, 3, 5] # 等价于 list(filter(lambda x: x % 2 ! 0, nums)) # [1, 3, 5] # ⚡ 返回不满足条件的元素避免写双重否定3.5accumulate(iterable, funcoperator.add)—— 累加 / 前缀运算from itertools import accumulate import operator # 前缀和 list(accumulate([1, 2, 3, 4, 5])) # [1, 3, 6, 10, 15] # 前缀积 list(accumulate([1, 2, 3, 4, 5], operator.mul)) # [1, 2, 6, 24, 120] # 自定义累积计算最大值变化 list(accumulate([5, 3, 8, 2, 9], max)) # [5, 5, 8, 8, 9] # 实战计算 running total 并跳过异常值 prices [100, 200, -999, 300, 150] def safe_add(acc, x): return acc x if x 0 else acc list(accumulate(prices, safe_add)) # [100, 300, 300, 600, 750]4. 排列组合三剑客from itertools import product, permutations, combinations, combinations_with_replacement letters [A, B, C] nums [1, 2] # 笛卡尔积嵌套循环 flat 版 list(product(letters, nums)) # [(A,1), (A,2), (B,1), (B,2), (C,1), (C,2)] # 排列有序不重复取 list(permutations(letters, 2)) # [(A,B), (A,C), (B,A), (B,C), (C,A), (C,B)] # 组合无序不重复取 list(combinations(letters, 2)) # [(A,B), (A,C), (B,C)] # 组合允许重复取 list(combinations_with_replacement([1, 2], 2)) # [(1, 1), (1, 2), (2, 2)]实战测试用例组合生成from itertools import product test_params { user_role: [admin, user, guest], is_login: [True, False], page: [home, profile, settings], } # 生成 3×2×3 18 个测试组合 for combo in product(*test_params.values()): params dict(zip(test_params.keys(), combo)) print(f测试: {params}) # run_test(**params)5. 分组神器groupbyfrom itertools import groupby data [ (fruit, apple), (fruit, banana), (drink, coffee), (drink, tea), (fruit, cherry), # ⚠️ 注意groupby 要求已排序 ] # 先排序再分组 data.sort(keylambda x: x[0]) for category, items in groupby(data, keylambda x: x[0]): print(f{category}: {[item[1] for item in items]}) # drink: [coffee, tea] # fruit: [apple, banana, cherry]⚠️核心坑groupby只对连续相同的元素分组不是 SQL 的 GROUP BY。务必预排序。# ❌ 未排序的后果 data [(a, 1), (b, 1), (a, 2)] for k, g in groupby(data, keylambda x: x[0]): print(k, list(g)) # a [(a, 1)] ← 第一个 a 组 # b [(b, 1)] # a [(a, 2)] ← 第二个 a 组同一个 key 分成了两组6. 组合技tee、slice、starmapfrom itertools import tee, islice, starmap # tee一个迭代器拆成多个独立副本 it (x for x in range(5)) it1, it2 tee(it, 2) list(it1) # [0, 1, 2, 3, 4] list(it2) # [0, 1, 2, 3, 4] ← 互不影响 # islice迭代器切片不创建中间列表 list(islice(range(100), 10, 20, 2)) # [10, 12, 14, 16, 18] # 对比 list(range(100))[10:20:2] ← 创建了 100 个元素的临时列表 # starmap带 * 展开的 map data [(2, 3), (4, 5), (6, 7)] list(starmap(pow, data)) # [8, 1024, 279936] ← pow(2,3), pow(4,5), pow(6,7)7. 避坑指南坑点说明解决❌groupby未排序返回的不是全量分组而是「连续段」分组分组前先sorted(data, key...)❌ 迭代器已耗尽itertools返回的都是迭代器只能遍历一次需要重复用 →list()转存或tee()❌ 无限迭代器没有终止条件count()/cycle()没 break 会死循环搭配takewhile/islice限流❌ 错误使用teetee的副本会共享内存如果一个消耗快一个消耗慢数据会在内存积压副本之间保持同步消费或用list()❌ 忽视性能优势chain写成a b、compress写成列表推导优先用itertools节省内存8. 总结itertools不是炫技工具是解决常见迭代问题的标准答案记住这几个高频组合chain展平、product笛卡尔积、groupby分组、accumulate前缀计算、compress掩码过滤所有工具都是惰性迭代器搭配islice/takewhile可以无限流式处理编写数据处理管道时尽量用itertools组合替代手写循环代码更短、含义更清晰、内存更省