3.2 itertools:迭代器函数
itertools包括一组用于处理序列数据集的函数。这个模块提供的函数是受函数式编程语言(如Clojure,Haskell,APL和SML)中类似特性的启发。其目的是要能快速处理,以及要高效地使用内存,而且可以联结在一起表述更复制的基于迭代的算法。
与使用列表的代码相比,基于迭代器的代码可以提供更好的内存消费特性。在真正需要数据之前,并不从迭代器生成数据,由于这个原因,不需要把所有数据都同时存储在内存中。这种“懒”处理模式可以减少交换及大数据集的其他副作用,从而改善性能。
除了itertools中定义的函数,这一节中的例子还会利用一些内置函数完成迭代。
3.2.1 合并和分解迭代器
chain()函数取多个迭代器作为参数,最后返回一个迭代器,它会生成所有输入迭代器的内容,就好像这些内容来自一个迭代器一样。
from itertools import *
for i in chain([1,2,3],['a','b','c']):
print(i ,end=' ')
print()
利用chain(),可以轻松地处理多个序列而不必构造一个很大的列表。
运行结果:
1 2 3 a b c
如果不能提前知道所有要结合的迭代器(可迭代对象),或者如果需要采用懒方式计算,那么可以使用chain.from_iterable()来构造这个链。
from itertools import *
def make_iterables_to_chain():
yield [1,2,3]
yield ['a','b','c']
for i in chain.from_iterable(make_iterables_to_chain()):
print(i,end=' ')
print()
运行结果:
1 2 3 a b c
内置函数zip()返回一个迭代器,它会把多个迭代器的元素结合到一个元组中。
for i in zip([1,2,3],['a','b','c']):
print(i)
与这个模块中的其他函数一样,返回值是一个可迭代的对象,会一次生成一个值。
运行结果:
(1, ‘a’)
(2, ‘b’)
(3, ‘c’)
第一个输入迭代器处理完时zip()就会停止。要处理所有输入(即使迭代器生成的值个数不同),则要使用zip_longest().
from itertools import *
r1 = range(3)
r2 = range(2)
print('zip stops early:')
print(list(zip(r1,r2)))
r1 = range(3)
r2 = range(2)
print('\nzip_longest processes all of the values:')
print(list(zip_longest(r1,r2)))
默认地,zip_longest()会把所有缺少的值替换为None。可以借助fillvalue参数来使用一个不同的替换值。
运行结果:
zip stops early:
[(0, 0), (1, 1)]
zip_longest processes all of the values:
[(0, 0), (1, 1), (2, None)]
islice()函数返回一个迭代器,它按索引从迭代器返回所选择的元素。
from itertools import *
print('Stop at 5:')
for i in islice(range(100),5):
print(i,end=' ')
print('\n')
print('Start at 5,Stop at 10:')
for i in islice(range(100),5,10):
print(i,end=' ')
print('\n')
print('By tens to 100:')
for i in islice(range(100),0,100,10):
print(i,end=' ')
print('\n')
islice()与列表的slice操作符参数相同,同样包括开始位置(start),结束位置(stop)和步长(step)。start和step参数是可选的。
运行结果:
Stop at 5:
0 1 2 3 4
Start at 5,Stop at 10:
5 6 7 8 9
By tens to 100:
0 10 20 30 40 50 60 70 80 90
tee()函数根据一个原输入迭代器返回多个独立的迭代器(默认为2个)。
from itertools import *
r = islice(count(),5)
i1,i2 = tee(r)
print('i1:',list(i1))
print('i2:',list(i2))
tee()的语义类似于UNIX tee工具,它会重复从输入读到的值,并把它们写至一个命名文件和标准输出。tee()返回的迭代器可以用来为并行处理的多个算法提供相同的数据集。
运行结果:
i1: [0, 1, 2, 3, 4]
i2: [0, 1, 2, 3, 4]
tee()创建的新迭代器会共享输入迭代器,所以创建了新迭代器后,不应再使用原迭代器。
from itertools import *
r = islice(count(),5)
i1 ,i2 = tee(r)
print('r:',end=' ')
for i in r:
print(i,end=' ')
if i > 1:
break
print()
print('i1:',list(i1))
print('i2:',list(i2))
如果原输入迭代器的一些值已经消费,新迭代器不会再生成这些值。
运行结果:
r: 0 1 2
i1: [3, 4]
i2: [3, 4]