使用示例1:创建处理数据的管道
具体描述:我们想以流水线式的形式对数据进行迭代处理(类似Unix下的管道)。比方说我们有海量的数据需要处理,但是没法完全的将数据加载到内存中去。
解决方案:生成器函数是一种实现管道机制的好方法(具体代码不做描述了,这里简单介绍下原理)
原理剖析:
1、yield语句表现为数据的生产者,for循环表现为数据的消费者;
2、由于处理过程的迭代特性,这里只会用到非常少的内存。
使用示例2:我们有一个嵌套序列,想将它扁平化处理为一列单独的值
解决方案:通过写一个带有yield from语句的递归生成器函数来解决
import collections
def flatten(items, ingore_types=(str, bytes)):
for x in items:
# isinstance(x, collections.Iterable) 检查是否有某个元素是可迭代的;
# 如果有,那么就用yield from将这个可迭代对象作为一种子例程进行递归,它将所有的值都产生出来
if isinstance(x, collections.Iterable) and not isinstance(x, ingore_types):
# not isinstance(x, ingore_types)是为了避免将字符串和字节串解释为可迭代对象,进而将他们展开为单独的一个个字符
yield from flatten(x)
else:
yield x
items = [1, 2, [3, 4, [5, 6], 7], 8]
for x in flatten(items):
print(x)
1
2
3
4
5
6
7
8
关于为何过滤not isinstance(x, ingore_types), 实例如下:
items = ['Dave', 'Paula', ['Thomas', 'Lewis']]
for x in flatten(items): # 输出了整个字符串(并没有迭代字符串)
print(x)
Dave
Paula
Thomas
Lewis
总结:
如果想编写生成器用来把其他的生成器当做子例程来调用,yield from是个不错的快捷方式。