itertools¶
itertools提供了操纵iterable对象的各种实用的函数。
关于Python中的iterable对象,我强烈推荐你去看PyCon 2013上Ned Batchelder给的talk: Loop Like A Native。
In [1]:
!python -V # 注意,我使用的Python版本比较高,可能包含新特性
Python 3.13.5
In [2]:
import itertools
dir(itertools) # 东西不多
Out[2]:
['__doc__', '__loader__', '__name__', '__package__', '__spec__', '_grouper', '_tee', '_tee_dataobject', 'accumulate', 'batched', 'chain', 'combinations', 'combinations_with_replacement', 'compress', 'count', 'cycle', 'dropwhile', 'filterfalse', 'groupby', 'islice', 'pairwise', 'permutations', 'product', 'repeat', 'starmap', 'takewhile', 'tee', 'zip_longest']
无穷迭代¶
count¶
In [3]:
# 生成无穷的整数序列
for i in itertools.count(start=1, step=2):
print(i, end="...")
if i >= 10:
break
1...3...5...7...9...11...
cycle¶
In [4]:
# 循环输出一个iterable
c = 0
for s in itertools.cycle("apple"):
print(s, end='')
c += 1
if c > 10:
break
appleapplea
repeat¶
In [5]:
# 重复一个item若干次,如果不指定次数就是无数次
for s in itertools.repeat('apple', 3):
print(s)
apple apple apple
组合迭代¶
product¶
In [6]:
# 笛卡尔积
# 注意,product会先【穷举】iterable对象中所有的东西,然后在计算笛卡尔积
# 所以不可以输入无穷iterable,否则会卡死
for i in itertools.product('123', 'abc'):
print(i)
('1', 'a') ('1', 'b') ('1', 'c') ('2', 'a') ('2', 'b') ('2', 'c') ('3', 'a') ('3', 'b') ('3', 'c')
In [7]:
# 自己和自己笛卡尔积
for i in itertools.product('abc', repeat=2):
print(i)
('a', 'a') ('a', 'b') ('a', 'c') ('b', 'a') ('b', 'b') ('b', 'c') ('c', 'a') ('c', 'b') ('c', 'c')
permutations¶
In [8]:
# 全排列
for i in itertools.permutations(range(3)):
print(i)
(0, 1, 2) (0, 2, 1) (1, 0, 2) (1, 2, 0) (2, 0, 1) (2, 1, 0)
In [9]:
# 部分排列
for i in itertools.permutations("apple", r=2):
# 注意这里面的两个p视为不同的对象
print(i)
('a', 'p') ('a', 'p') ('a', 'l') ('a', 'e') ('p', 'a') ('p', 'p') ('p', 'l') ('p', 'e') ('p', 'a') ('p', 'p') ('p', 'l') ('p', 'e') ('l', 'a') ('l', 'p') ('l', 'p') ('l', 'e') ('e', 'a') ('e', 'p') ('e', 'p') ('e', 'l')
combinations¶
In [10]:
# 组合
for i in itertools.combinations(range(3), r=2):
print(i)
(0, 1) (0, 2) (1, 2)
combinations_with_replacement¶
In [11]:
# 有放回组合抽样
for i in itertools.combinations_with_replacement(range(3), r=2):
print(i)
(0, 0) (0, 1) (0, 2) (1, 1) (1, 2) (2, 2)
拼好迭¶
accumulate¶
In [12]:
# 累加
for i in itertools.accumulate(range(10)):
print(i, end='...')
0...1...3...6...10...15...21...28...36...45...
In [13]:
# 累乘
for i in itertools.accumulate(
itertools.repeat(1.1, 5), # 1.1 倍增
func=lambda x, y: x * y,
initial=100, # 从100开始
):
print(format(i, ".2f"))
100.00 110.00 121.00 133.10 146.41 161.05
如果你熟悉标准库,会发现还有一个functools.reduce函数和accumulate很像:
In [14]:
from functools import reduce
reduce(lambda x, y: x + y, range(10))
Out[14]:
45
不过reduce只会返回最后的结果。
batched¶
Python 3.12+才有这个函数
In [15]:
# 一批一批取出对象
# n是batch size
# strict为真的时候,需要可迭代对象的长度被n整除,否则跑出ValueError
for b in itertools.batched(range(10), n=3, strict=False):
print(b)
(0, 1, 2) (3, 4, 5) (6, 7, 8) (9,)
chain¶
In [16]:
# 把若干个iterable对象拼起来
for i in itertools.chain(range(3), range(5), range(2)):
print(i, end='...')
0...1...2...0...1...2...3...4...0...1...
In [17]:
# 把嵌套的iterable对象拼起来
for i in itertools.chain.from_iterable(["apple", "juice"]):
print(i, end=" ")
a p p l e j u i c e
compress¶
In [18]:
# 根据selecotr去掉一些元素
for i in itertools.compress("apple", selectors=[1, 0, 0, 1, 1]):
print(i, end="")
ale
dropwhile¶
In [19]:
# 丢弃掉iterable中【前面几个】不满足条件的对象
# 直到有满足条件的对象出现
# 输出后面所有的对象
for i in itertools.dropwhile(lambda x: x > 5, [9, 6, 3, 1, 0, 8]):
print(i, end="...")
3...1...0...8...
takewhile¶
In [20]:
# takewhile反之
# 一旦有不满足条件的item,就停止迭代
for i in itertools.takewhile(lambda x: x > 5, [9, 6, 3, 1, 0, 8]):
print(i, end="...")
9...6...
filterfalse¶
In [21]:
# 丢弃掉iterable中【所有】不满足条件的对象
# 只输出满足条件的对象
for i in itertools.filterfalse(lambda x: x > 5, [9, 6, 3, 1, 0, 8]):
print(i, end="...")
3...1...0...
In [22]:
# 顺带一提,built-in的filter和filterfalse效果类似
for i in filter(lambda x: x > 5, [9, 6, 3, 1, 0, 8]):
print(i, end='...')
9...6...8...
groupby¶
In [23]:
# groupby默认按照iterable中每个对象的id()作为key进行分组
# 每当遇到和上一组不同的key就开辟一个新组
# 因此下面的例子中p会出现两个分组
for k, g in itertools.groupby("apple ppi"):
print(k, list(g))
a ['a'] p ['p', 'p'] l ['l'] e ['e'] [' '] p ['p', 'p'] i ['i']
islice¶
In [24]:
a_set = set("apple")
a_set
Out[24]:
{'a', 'e', 'l', 'p'}
In [25]:
# 集合是不可以切片的
a_set[0:3]
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[25], line 2 1 # 集合是不可以切片的 ----> 2 a_set[0:3] TypeError: 'set' object is not subscriptable
In [26]:
# islice可以让一些不支持切片操作的iterable进行切片
# 但是不支持负数切片!
for i in itertools.islice(a_set, 0, 3):
print(i, end='...')
p...e...l...
In [27]:
# 注意这里 a_set 中元素的顺序并非字典顺序
list(a_set)
Out[27]:
['p', 'e', 'l', 'a']
pairwise¶
Python 3.10+才有这个函数
In [28]:
# 有重叠地,一对一对遍历iterable中的对象
for i in itertools.pairwise("apple"):
print(i)
('a', 'p') ('p', 'p') ('p', 'l') ('l', 'e')
In [29]:
# 例如我们要计算一阶差分
for i in itertools.pairwise([3, 1, 2, 6, 9]):
print(i[1] - i[0], end="...")
-2...1...4...3...
starmap¶
In [30]:
# map大家比较熟悉,就是把一个函数作用到iterable的每一个对象中
# f(i) for i in iterable
list(map(sum, [(1, 2), (4, 6)]))
Out[30]:
[3, 10]
In [31]:
def add(a, b):
return f"{a}+{b}={a + b}"
In [32]:
# starmap则是把iterable的每个对象解包传入到函数中
# f(*i) for i in iterable
list(itertools.starmap(add, [(1, 2), (4, 6)]))
Out[32]:
['1+2=3', '4+6=10']
tee¶
In [33]:
def gen(n=5):
for i in range(n):
print(f'{i} is computed...')
yield i
In [34]:
g = gen()
# 对于一个生成器来说,我们只能遍历一次
# 第二次遍历的时候就空了
list(g), list(g)
0 is computed... 1 is computed... 2 is computed... 3 is computed... 4 is computed...
Out[34]:
([0, 1, 2, 3, 4], [])
In [35]:
it1, it2 = itertools.tee(gen(), 2)
In [36]:
# 可以看到,我们依然只计算了一次
# 【并且计算的过程是在迭代的时候进行的,创建tee迭代器的时候不会计算】
# 但是可以把输出流复制很多份
list(it1), list(it2)
0 is computed... 1 is computed... 2 is computed... 3 is computed... 4 is computed...
Out[36]:
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])
zip_longest¶
In [37]:
# 如果其中某个iterable不够长,就用None来补充
for t in itertools.zip_longest("apple", range(3), fillvalue=None):
print(*t)
a 0 p 1 p 2 l None e None
In [38]:
# built-in的zip相当于是zip_shortest
for t in zip("apple", range(3)):
print(*t)
a 0 p 1 p 2
more-itertools¶
如果你觉得这些itertools都是脱裤子放屁,不如自己手撸。
那么我必须向你介绍更多的屁:more-itertools
事实上,itertools作为标准库是用C实现的,自己手撸可能真不如标准库。而more-itertools是一个纯Python实现的库,封装了很多好用的小工具。
In [39]:
!pip install more-itertools
Requirement already satisfied: more-itertools in /Users/admin/miniconda3/lib/python3.13/site-packages (10.7.0)
In [40]:
import more_itertools
In [41]:
more_itertools.is_prime(5999)
Out[41]:
False
In [42]:
list(more_itertools.factor(5999))
Out[42]:
[7, 857]
最后更新: 2025-07-25 10:10:10
创建日期: 2025-07-25 10:10:10
创建日期: 2025-07-25 10:10:10
广告
人要恰饭的嘛🤑🤑