通过上面的文章我们知道了如何定义生成器以及如何启动生成器输出其中的元素,但是我们还遗留了一个小问题就是send()函数。本节课简单介绍下:
学习send()之前先看下面的代码,如下是一个普通的生成器函数,内部yield了2个值。
# -*- coding: utf-8 -*-
def test(num):
for i in range(num):
yield i
obj = test(2)
value = next(obj) # 第1次调用
print(value)
value = next(obj) # 第2次调用
print(value)
0
1
yield的返回值作为生成器的元素在调用时被输出,如果在上面的生成器函数内部把yield i 变成temp = yield i后你觉得会是什么后果?是否能改变生成器的特性呢?另外,temp会有什么结果嘛?实际看一看:
# -*- coding: utf-8 -*-
def test(num):
for i in range(num):
temp = yield i
print('temp:',temp)
obj = test(2)
value = next(obj) # 第1次调用,执行yield 0后暂停
print(value)
value = next(obj) # 第2次调用,接着yield 0 往下执行,直到二次循环yield 1
print(value)
0
temp: None
1
由此可见:
1、yield i本身并没有把 i值赋给temp,因为temp打印出来是None。
2、生成器函数本身的特性并无变化,生成器函数内部执行到yield后依然会暂停(所以才打印1次temp),第2次调用仍然是从yield后的代码开始执行。(如果不理解请继续翻看本文开头说的那篇文章)。
但是如何做到让yield i这句话可以有个值返回给temp呢,这就需要send函数。请注意下面的代码中yield i此时会被当做一个整体被赋值并且传给temp(传的值就是send函数的参数),而并非是yield i把i传值给temp。
# -*- coding: utf-8 -*-
def test(num):
for i in range(num):
temp = yield i # 这句话可以接收值,可以产出值
print('temp:',temp)
obj = test(2)
value = obj.send(None)
print(value)
value = obj.send('python66')
print(value)
0
temp: python66
1
第一次调用生成器函数时,不能使用send发送一个非None的值,否则会出错的,在send一个非None值之前必须启动一次生成器。而send(None)就可以做到启动生成器。
can't send non-None value to a just-started generator
1、请记住,temp = yield i这句话可以接收值,可以产出值!分两步从右往左执行。
2、第一次send(None)时,启动生成器,从生成器函数的第一行代码开始执行,直到第一次执行yield i 后跳出生成器函数。这个过程中,并没有执行到temp被赋值。
3、再次执行send('python66')时,进入生成器函数,此时,yield i会看做一个整体,像一个中间变量一样被赋值并且传回给temp。即相当于把python66赋值给temp(并不是把i的值赋给temp)。这个过程里yield i 中i的值依然会作为生成器的元素在调用时输出。