yield和next函数
首先看以下代码,根据以往的知识,tmp=flatten(items),这两者是相当的,所以print的结果不会改变,但事实并非如此。
from collections import Iterable
def flatten(items, ignore_types=(str, bytes)):
for x in items:
if isinstance(x, Iterable) and not isinstance(x, ignore_types):
yield from flatten(x)
else:
yield x
items=[[1,2,3],[4,5,6],[7,8,9]]
tmp=flatten(items)
print(next(flatten(items)))
print(next(flatten(items)))
print(next(flatten(items)))
tmp=flatten(items)
print(next(tmp))
print(next(tmp))
print(next(tmp))
这是为什么?关键就在于yield和next函数。
一次yield相当于return,但yield不会彻底终结这个函数,而是保留阻塞当前函数的状态,等待下一次next函数调用后再启动。
def logh(n):
now = 0
while now < n:
yield now
now += 1
print(list(logh(10)))
这就是简单使用yield生成器产生序列结果,更常见的有:
[x*x for x in range(10)]
生成0到9的平方数
这里用type也可以查看类型:两者的显示都是generator(生成器)类型
print(type(x*x for x in range(10)))
print(type(logh(10)))
在难以理解时甚至可以粗暴认为generator就是代表着列表中的元素,虽然投机取巧,但这样往往是捷径。
generator.send()
generator.send()函数是生成器的一个方法,它允许我们在生成器函数中向生成器发送数据。当我们调用generator.send(value)时,生成器会从上一次的yield语句处继续执行,并将value赋值给上一次yield的返回值。如果生成器已经到达了结尾,那么调用 generator.send() 将会抛出一个 StopIteration 异常。它的返回值就是该生成器调用一次next()的返回值。
def jumping_range(N):
index = 0
while index < N:
# 通过send()发送的信息将赋值给jump
jump = yield index#这就相当于return 和 receive结合,return当前值,也接受外部输入
if jump is None:
jump = 1
index += jump
if __name__ == '__main__':
itr = jumping_range(5)
print(next(itr))
print(itr.send(2))
print(next(itr))
print(itr.send(-1))