罗列 Python 标准库中的生成器函数 (3)

2018-11-22  本文已影响0人  SuperDi

上一篇 ( 罗列 Python 标准库中的生成器函数 (2) ) 我们列举了 用于合并多个可迭代对象的生成器函数 ,接下来我们继续列举标准库中剩下的生成器函数

有些生成器函数会从一个元素中产出多个值,扩展输入的可迭代对象,如下所示。

4、把输入的各个元素扩展成多个输出元素的生成器函数
模块 函数 说明
itertools combinations(it, out_len) 把 it 产出的 out_len 个元素组合在一起,然后产出
itertools combinations_with_replacement(it,out_len) 把 it 产出的 out_len 个元素组合在一起,然后产出,包含相同元素的组合
itertools count(start=0, step=1) 从 start 开始不断产出数字,按step 指定的步幅增加
itertools cycle(it) 从 it 中产出各个元素,存储各个元素的副本,然后按顺序重复不断地产出各个元素
itertools permutations(it, out_len=None) 把 out_len 个 it 产出的元素排列在一起,然后产出这些排列;out_len的默认值等于 len(list(it))
itertools repeat(item, [times]) 重复不断地产出指定的元素,除非提供 times,指定次数

itertools 模块中的 count 和 repeat 函数返回的生成器“无中生有”:这两个函数都不接受可迭代的对象作为输入。生成器函数第一篇中见过itertools.count 函数。cycle 生成器会备份输入的可迭代对象,然后重复产出对象中的元素。如下演示 count、repeat 和 cycle的用法(count()生成器函数在第一篇已经讲过了,此处按照分类再次演示):

>>> ct = itertools.count() # 1
>>> next(ct) # 2
0
>>> next(ct), next(ct), next(ct) # 3
(1, 2, 3)
>>> list(itertools.islice(itertools.count(1, .3), 3)) # 4
[1, 1.3, 1.6]
>>> cy = itertools.cycle('ABC') # 5
>>> next(cy)
'A'
>>> list(itertools.islice(cy, 7)) # 6
['B', 'C', 'A', 'B', 'C', 'A', 'B']
>>> rp = itertools.repeat(7) # 7
>>> next(rp), next(rp)
(7, 7)
>>> list(itertools.repeat(8, 4)) # 8
[8, 8, 8, 8]
>>> list(map(operator.mul, range(11), itertools.repeat(5))) # 9
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]

1、使用 count 函数构建 ct 生成器。
2、获取 ct 中的第一个元素。
3、不能使用 ct 构建列表,因为 ct 是无穷的,所以我获取接下来的 3个元素。
4、如果使用 islice 或 takewhile 函数做了限制,可以从 count 生成器中构建列表。
5、使用 'ABC' 构建一个 cycle 生成器,然后获取第一个元素——'A'。
6、只有受到 islice 函数的限制,才能构建列表;这里获取接下来的 7个元素。
7、构建一个 repeat 生成器,始终产出数字 7。
8、传入 times 参数可以限制 repeat 生成器生成的元素数量:这里会生成 4 次数字 8。
9、repeat 函数的常见用途:为 map 函数提供固定参数,这里提供的是乘数 5。

在 itertools 模块的文档中(https://docs.python.org/3/library/itertools.html), combinations、combinations_with_replacement和 permutations 生成器函数,连同 product 函数,称为组合学生成器(combinatoric generator)。itertools.product 函数和其余的组合学函数有紧密的联系,如以下示例所示:

>>> list(itertools.combinations('ABC', 2)) # 1
[('A', 'B'), ('A', 'C'), ('B', 'C')]
>>> list(itertools.combinations_with_replacement('ABC', 2)) # 2
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C')]
>>> list(itertools.permutations('ABC', 2)) # 3
[('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]
>>> list(itertools.product('ABC', repeat=2)) # 4
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'),
('C', 'A'), ('C', 'B'), ('C', 'C')]

1、'ABC' 中每两个元素(len()==2)的各种组合;在生成的元组中,
元素的顺序无关紧要(可以视作集合)。
2、'ABC' 中每两个元素(len()==2)的各种组合,包括相同元素的组
合。
3、'ABC' 中每两个元素(len()==2)的各种排列;在生成的元组中,
元素的顺序有重要意义。
4、'ABC' 和 'ABC'(repeat=2 的效果)的笛卡儿积。

接下来要说的的最后一组生成器函数用于产出输入的可迭代对象中的全部元素,不过会以某种方式重新排列。其中有两个函数会返回多个生成器,分别是 itertools.groupby 和 itertools.tee。这一组里的另一个生成器函数,内置的 reversed 函数,是列举的所述函数中唯一一个不接受可迭代的对象,而只接受序列为参数的函数。这在情理之中,因为reversed 函数从后向前产出元素,而只有序列的长度已知时才能工作。不过,这个函数会按需产出各个元素,因此无需创建反转的副本。另外 itertools.product 函数划分为用于合并的生成器,已经列在了表3、用于合并多个可迭代对象的生成器函数中,因为那一组函数都处理多个可迭代的对象,而下面所列的的生成器最多只能接受一个可迭代的对象

4、用于重新排列元素的生成器函数
模块 函数 说明
itertools groupby(it,key=None) 产出由两个元素组成的元素,形式为 (key,group),其中 key 是分组标准,group 是生成器,用于产出分组里的元素
(内置) reversed(seq) 从后向前,倒序产出 seq 中的元素;seq 必须是序列,或者是实现了 reversed 特殊方法的对象
itertools tee(it, n=2) 产出一个由 n 个生成器组成的元组,每个生成器用于单独产出输入的可迭代对象中的元素

以下先演示 itertools.groupby 函数和内置的 reversed 函数的用法。注意,itertools.groupby 假定输入的可迭代对象要使用分组标准排序;即使不排序,至少也要使用指定的标准分组各个元素。

>>> list(itertools.groupby('LLLLAAGGG')) # 1
[('L', <itertools._grouper object at 0x102227cc0>),
('A', <itertools._grouper object at 0x102227b38>),
('G', <itertools._grouper object at 0x102227b70>)]
>>> for char, group in itertools.groupby('LLLLAAAGG'): # 2
... print(char, '->', list(group))
...
L -> ['L', 'L', 'L', 'L']
A -> ['A', 'A',]
G -> ['G', 'G', 'G']
>>> animals = ['duck', 'eagle', 'rat', 'giraffe', 'bear',
... 'bat', 'dolphin', 'shark', 'lion']
>>> animals.sort(key=len) # 3
>>> animals
['rat', 'bat', 'duck', 'bear', 'lion', 'eagle', 'shark',
'giraffe', 'dolphin']
>>> for length, group in itertools.groupby(animals, len): # 4
... print(length, '->', list(group))
...
3 -> ['rat', 'bat']
4 -> ['duck', 'bear', 'lion']
5 -> ['eagle', 'shark']
7 -> ['giraffe', 'dolphin']
>>> for length, group in itertools.groupby(reversed(animals), len): # 5
... print(length, '->', list(group))
...
7 -> ['dolphin', 'giraffe']
5 -> ['shark', 'eagle']
4 -> ['lion', 'bear', 'duck']
3 -> ['bat', 'rat']
>>>

1、groupby 函数产出 (key, group_generator) 这种形式的元组。
2、处理 groupby 函数返回的生成器要嵌套迭代:这里在外层使用 for循环,内层使用列表推导。
3、为了使用 groupby 函数,要排序输入;这里按照单词的长度排序。
4、再次遍历 key 和 group 值对,把 key 显示出来,并把 group 扩展成列表。
5、这里使用 reverse 生成器从右向左迭代 animals。

这一组里的最后一个生成器函数是 iterator.tee,这个函数只有一个作用:从输入的一个可迭代对象中产出多个生成器,每个生成器都可以产出输入的各个元素。产出的生成器可以单独使用,如以下示例所示。

[<itertools._tee object at 0x10222abc8>, <itertools._tee object at 0x10222ac08>]
>>> g1, g2 = itertools.tee('ABC')
>>> next(g1)
'A'
>>> next(g2)
'A'
>>> next(g2)
'B'
>>> list(g1)
['B', 'C']
>>> list(g2)
['C']
>>> list(zip(*itertools.tee('ABC')))
[('A', 'A'), ('B', 'B'), ('C', 'C')]

在三篇介绍生成器函数示例中多次把不同的生成器函数组合在一起使用。其实这就是这些函数的优秀特性:这些函数的参数都是生成器,而返回的结果也是生成器,因此能以很多不同的方式结合在一起使用

完毕~
上一篇下一篇

猜你喜欢

热点阅读