Python 的 itertools:别再手写循环做组合与分组

举报
yd_268445051 发表于 2026/11/12 09:59:51 2026/11/12
【摘要】 写 Python 时,很多循环其实是在重复造轮子:把几个列表拼成一个、取前 N 条、按某个键分组、生成所有两两组合。手写这些循环不难,但容易写错边界,也难一眼看出意图。itertools 就是标准库里专门干这件事的工具箱:它提供的都是惰性迭代器,用多少算多少,不会一次把结果全算出来占内存。先看最常用的 chain,把多个可迭代对象首尾相接:from itertools import chai...

写 Python 时,很多循环其实是在重复造轮子:把几个列表拼成一个、取前 N 条、按某个键分组、生成所有两两组合。手写这些循环不难,但容易写错边界,也难一眼看出意图。itertools 就是标准库里专门干这件事的工具箱:它提供的都是惰性迭代器,用多少算多少,不会一次把结果全算出来占内存。

先看最常用的 chain,把多个可迭代对象首尾相接:

from itertools import chain

pages = [1, 2, 3]
more = [4, 5]
for n in chain(pages, more):
    print(n)  # 1, 2, 3, 4, 5

不用先 pages + more 拼出一个新列表,尤其当两边都是大文件或生成器时,chain 不复制、不占额外内存,读到哪算到哪。chain.from_iterable 还能把“列表的列表”拍平一层,处理分批读到的数据很顺手。

第二个顺手的是 islice,给迭代器切一刀。普通切片 data[10:20] 只对列表有效,生成器没有下标,切了就报错:

from itertools import islice

def lines():
    with open("app.log") as f:
        yield from f

first_ten = list(islice(lines(), 10))

islice 只往前走十步就停,不会把整个文件读进来。看日志前几行、取分页的第一页,都是它的活。注意它是有去无回的:切过的部分消费掉了,不能再倒回去。

分组用 groupby,但有一个前提常被忽略:它只把连续相同的元素分到一组,输入必须先按同一个键排好序:

from itertools import groupby

orders = [("北京", 120), ("上海", 80), ("北京", 90)]
orders.sort(key=lambda o: o[0])
for city, group in groupby(orders, key=lambda o: o[0]):
    print(city, sum(o[1] for o in group))

没排序就直接 groupby,同一个城市会出现两次,分组结果就错了。排序是调用方的责任,groupby 不替你做。

最后是组合类工具,写测试数据和排列时很省事:

from itertools import combinations, product

list(combinations(["A", "B", "C"], 2))
# [('A', 'B'), ('A', 'C'), ('B', 'C')]
list(product([1, 2], ["x", "y"]))
# [(1, 'x'), (1, 'y'), (2, 'x'), (2, 'y')]

combinations 不考虑顺序、每个元素只用一次,适合“从 N 个里挑两个”的场景;product 是笛卡尔积,适合参数组合。两者返回的都是迭代器,组合数爆炸时也不会先把所有结果算出来撑爆内存——但这也意味着真要全量展开前,先想清楚数量级。

用 itertools 的思路就一句话:先想清楚你要的是拼接、切片、分组还是组合,找对应的工具,而不是一上来就写 for 循环加临时列表。循环写得越少,边界错得越少,读代码的人也越快明白你要干什么。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。