标准库提供了很多生成器,有用于逐行迭代纯文本文件的对象,还有出色的 os.walk 函数。 这个函数在遍历目录树的过程中产出文件名,因此递归搜索文件系统像 for 循环那样简单。
os.walk 生成器函数的作用令人赞叹,不过本节专注于通用的函数:参数为任意的可迭代对象,返回值是生成器,用于生成选中的、计算出的 和重新排列的元素。
表14-1 用于过滤的生成器函数:从输入的可迭代对象中产出元素的子集,而且不修改元素本身。
- filter(predicate, it):把 it 中的各个元素传给 predicate,如果 predicate(item) 返回真值,那么产出对应的元素;如果 predicate 是 None,那么只产出真值元素;
- filterfalse(predicate, it):与 filter 函数的作用类似,不过 predicate 的逻辑是相反的:predicate 返回假值时产出对应的元素;
- compress(it, selector_it):并行处理两个可迭代对象,如果 selector_it 中的元素是真值,产出 it 中对应的元素,当任一个可迭代对象到头后,停止迭代;
- islice(it, start, stop, step=1):产出 it 的切片,作用类似于 s[:stop] 或 s[start:stop:step],不过 it 可以是任何可迭代的对象,而且这个函数实现的是惰性操作;
-
dropwhile(predicate, it):处理 it,跳过 predicate 的计算结果为真值的元素,然后产出剩下的各个元素(不再进一步检查);
-
takewhile(predicate, it):predicate 返回真值时产出对应的元素,然后立即停止,不再继续检查;
def vowel(z):
return z.lower() in 'aeiou'
# filter(predicate, it) ==============================================
print(list(filter(vowel, 'Aardvark'))) # ['A', 'a', 'a']
# filterfalse(predicate, it) =========================================
print(list(filterfalse(vowel, 'Aardvark'))) # ['r', 'd', 'v', 'r', 'k']
# compress(it, selector_it) ==========================================
print(list(compress('Aardvark', (1, 0, 1, 1, 0, 1)))) # ['A', 'r', 'd', 'a']
# islice(it, start, stop, step=1) ====================================
print(list(islice('Aardvark', 4))) # ['A', 'a', 'r', 'd']
print(list(islice('Aardvark', 4, 7))) # ['v', 'a', 'r']
print(list(islice('Aardvark', 1, 7, 2))) # ['a', 'd', 'a']
# dropwhile(predicate, it) ===========================================
print(list(dropwhile(vowel, 'Aardvark'))) # ['r', 'd', 'v', 'a', 'r', 'k']
# takewhile(predicate, it) ===========================================
print(list(takewhile(vowel, 'Aardvark'))) # ['A', 'a']
表14-2 用于映射的生成器函数:在输入的单个可迭代对象中的各个元素上做计算,然后返回结果。
(这里所说的“映射”与字典没有关系,而与内置的 map 函数有关)
-
map(func, it1, [it2, ...]):把 it 中的各个元素传给 func,产出结果;如果传入 N 个可迭代的对象,那么 func 必须能接受 N 个参数,而且要并行处理各个可迭代的对象;
-
starmap(func, it):将 it 中的元素,以元组拆包的形式传递给 func,产出结果;
-
enumerate(iterable, start=0):产出由两个元素组成的元组,结构是 :(index, item),其中 index 从 start 开始计数,item 则从 iterable 中获取;
-
accumulate(it, [func]):产出累积的总和;如果提供了 func,那么把前两个元素传给它,然后把计算结果和下一个元素传给它,以此类推,最后产出结果;
import operator
from itertools import *
# map(func, it1, [it2, ...]) =======================================
m = [1, 2, 3]
n = ['a', 'b', 'c']
o = ['x', 'y', 'z']
def func(i, j, k):
return i, j, k
print(list(map(func, m, n, o))) # [(1, 'a', 'x'), (2, 'b', 'y'), (3, 'c', 'z')]
# enumerate(iterable, start=0) =====================================
x = ['a', 'b', 'c']
print(list(enumerate(x))) # [(0, 'a'), (1, 'b'), (2, 'c')]
print(list(enumerate(x, start=1))) # [(1, 'a'), (2, 'b'), (3, 'c')]
# accumulate(it, [func]) ===========================================
sample = [5, 4, 2, 8, 7, 6, 3, 0, 9, 1]
# 求和
list(accumulate(sample)) # [5, 9, 11, 19, 26, 32, 35, 35, 44, 45]
# 取最小值
list(accumulate(sample, min)) # [5, 4, 2, 2, 2, 2, 2, 0, 0, 0]
# 阶乘
list(accumulate(range(1, 11), operator.mul)) # [1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
# starmap(func, it) ================================================
def func(*it):
return it
y = ['a1', 'b2', 'c3']
print(list(starmap(func, x))) # [('a', '1'), ('b', '2'), ('c', '3')]
表14-3 合并多个可迭代对象的生成器函数:
-
zip(it1, ..., itN):并行从输入的 N 个可迭代对象中获取元素,产出由 N 个元素组成的元组,只要有一个可迭代对象到头了,就默默地停止;
-
zip_longest(it1, ..., itN, fillvalue=None):并行从输入的 N 个可迭代对象中获取元素,产出由 N 个元素组成的元组,等到最长的可迭代对象到头后才停止,空缺的值使用 fillvalue 填充;
-
chain(it1, ..., itN):先产出 it1 中的所有元素,然后产出 it2 中的所有元素,以此类推,无缝连接在一起;
-
chain.from_iterable(it):产出 it 生成的各个可迭代对象中的元素,一个接一个,无缝连接在一起;it 应该产出可迭代的元素,例如可迭代的对象列表;
-
product(it1, ..., itN, repeat=1):计算笛卡儿积:从输入的各个可迭代对象中获 取元素,合并成由 N 个元素组成的元组,与嵌套的 for 循环效果一样;repeat 指明重复处理多少次输入的可迭代对象;
from itertools import *
# zip(it1, ..., itN) ==============================================
print(list(zip('ABC', range(5)))) # [('A', 0), ('B', 1), ('C', 2)]
print(list(zip('ABC', range(5), [10, 20, 30, 40]))) # [('A', 0, 10), ('B', 1, 20), ('C', 2, 30)]
# zip_longest(it1, ..., itN, fillvalue=None) ======================
print(list(zip_longest('ABC', range(5)))) # [('A', 0), ('B', 1), ('C', 2), (None, 3), (None, 4)]
print(list(zip_longest('ABC', range(5), fillvalue='?'))) # [('A', 0), ('B', 1), ('C', 2), ('?', 3), ('?', 4)]
# chain(it1, ..., itN) ============================================
print(list(chain('ABC', range(2)))) # ['A', 'B', 'C', 0, 1]
print(list(chain(enumerate('ABC')))) # [(0, 'A'), (1, 'B'), (2, 'C')]
# chain.from_iterable(it) =========================================
print(list(chain.from_iterable(enumerate('ABC')))) # [0, 'A', 1, 'B', 2, 'C']
# product(it1, ..., itN, repeat=1) ================================
list(product('ABC', range(2))) # [('A', 0), ('A', 1), ('B', 0), ('B', 1), ('C', 0), ('C', 1)]
list(product('ABC', repeat=2))
# [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C')]
rows = product('AB', range(2), repeat=2)
for row in rows:
print(row)
# ('A', 0, 'A', 0)
# ('A', 0, 'A', 1)
# ('A', 0, 'B', 0)
# ('A', 0, 'B', 1)
# ('A', 1, 'A', 0)
# ('A', 1, 'A', 1)
# ('A', 1, 'B', 0)
# ('A', 1, 'B', 1)
# ('B', 0, 'A', 0)
# ('B', 0, 'A', 1)
# ('B', 0, 'B', 0)
# ('B', 0, 'B', 1)
# ('B', 1, 'A', 0)
# ('B', 1, 'A', 1)
# ('B', 1, 'B', 0)
# ('B', 1, 'B', 1)
表14-4 用于重新排列元素的生成器函数:
-
reversed(seq):从后向前,倒序产出 seq 中的元素;seq 必须是序列,或者是实现了 __reversed__ 特殊方法的对象;
-
groupby(it,key=None):产出由两个元素组成的元素,形式为 (key, group),其中 key 是分组标准,group 是生成器, 用于产出分组里的元素;
from itertools import *
# reversed(seq) =================================================
x = ['a', 'c', 'd', 1, 'g', 'z']
c = reversed(x)
print(list(c)) # ['z', 'g', 1, 'd', 'c', 'a']
# groupby(it,key=None) =========================================
print(list(groupby('LLLLAAGGG')))
# [('L', <itertools._grouper object at 0x1100a04a8>),
# ('A', <itertools._grouper object at 0x1100f2390>),
# ('G', <itertools._grouper object at 0x1100f2400>)]
for char, group in groupby('LLLLAAAGG'):
print(char, '->', list(group))
# L -> ['L', 'L', 'L', 'L']
# A -> ['A', 'A', 'A']
# G -> ['G', 'G']
animals = ['duck', 'eagle', 'rat', 'giraffe', 'bear', 'bat', 'dolphin', 'shark', 'lion']
for length, group in groupby(animals, len):
print(length, '->', list(group))
# 4 -> ['duck']
# 5 -> ['eagle']
# 3 -> ['rat']
# 7 -> ['giraffe']
# 4 -> ['bear']
# 3 -> ['bat']
# 7 -> ['dolphin']
# 5 -> ['shark']
# 4 -> ['lion']
animals.sort(key=len)
for length, group in groupby(animals, len):
print(length, '->', list(group))
# 3 -> ['rat', 'bat']
# 4 -> ['duck', 'bear', 'lion']
# 5 -> ['eagle', 'shark']
# 7 -> ['giraffe', 'dolphin']
表 14-5 可迭代的归约函数:接受一个可迭代的对象,然后返回单个结果的函数叫“归约”函数。
-
all(it):it 中的所有元素都为真值时返回 True,否则返回 False,all([]) 返回 True;
-
any(it):只要 it 中有元素为真值就返回 True,否则返回 False,any([]) 返回 False;
-
max(it, [key=,] [default=]):返回 it 中值最大的元素;key 是排序函数,与 sorted 函数中的一样;如果可迭代的对象为空,返回 default;
-
min(it, [key=,] [default=]):返回 it 中值最小的元素;key 是排序函数,与 sorted 函数中的一样;如果可迭代的对象为空,返回 default;
-
reduce(func, it, [initial]):把 it 的前两个元素传给 func,然后把计算结果和第三个元素传给 func,以此类推,返回最后的结果;如果提供了 initial,把它当作第一个元素传入;
-
sum(it, start=0):it 中所有元素的总和,如果提供可选的 start,会把它加上(计算浮点数的加法时,可以使用 math.fsum 函数提高精度);