yield把含有循环的函数变成生成器(generator),同时变为可以延迟执行,不占内存,调用的时候才去生成。
1. 首先看一个使用for循环打印数字的例子:
def get_seq(n):
for i in range(n):
print(i)
get_seq(3)
输出:
0
1
2
2. 如果我们改造一下,在for循环里面的i前面加上yield:
def get_seq(n):
for i in range(n):
yield i
print(type(get_seq),type(get_seq(3)))
for i in get_seq(3):
print(i)
输出:
<class 'function'> <class 'generator'>
0
1
2
我们可以看到get_seq还是一个函数,但是如果传入了参数,它的返回值就变成了一个生成器,我们可以通过这个生成器构造一个迭代器(iterator),再使用for循环和上面一下打印出序列。
3. 除了使用for循环迭代输出,我们还可以使用next直接获取生成器每次生成的值:
def get_seq(n):
for i in range(n):
yield i
seq = get_seq(3)
print(next(seq))
print("pause")
print(next(seq))
print(next(seq))
输出:
0
pause
1
2
注意这里因为传入的参数是3,所以next也只能执行3次,再执行next就会报错了。
4. 使用send方法向生成器内部发送信息:
def get_seq(n):
for i in range(n):
tmp = yield i
print("receive:",tmp)
seq = get_seq(3)
print(next(seq))
print(seq.send("-1"))
print(seq.send("-2"))
输出:
0
receive: -1
1
receive: -2
2
可以看到调用next函数时默认返回的是每次变化生成的 i
,并且到yield那行就直接返回了
,不会执行下面的print的代码了。
而如果调用send函数,相当于把send函数的参数传递给了tmp
,然后继续调用下面的print代码,注意send函数本身还是会返回每次变化生成的i
。因此执行到2后面不能再调用next或者send了,否则会报错。