生成器对象是一个迭代器。但是它比迭代器对象多了一些方法,它们包括send方法,throw方法和close方法。这些方法,主要是用于外部与生成器对象的交互。本文先介绍send方法。
send方法有一个参数,该参数指定的是上一次被挂起的yield语句的返回值。这样说起来比较抽象,看下面的例子。
def MyGenerator():
value = (yield 1)
value = (yield value)
gen = MyGenerator()
print gen.next()
print gen.send(2)
print gen.send(3)
输出的结果如下
1
2
Traceback (most recent call last):
File "test.py", line 18, in <module>
print gen.send(3)
StopIteration
上面代码的运行过程如下。
当调用gen.next()方法时,python首先会执行MyGenerator方法的yield 1语句。由于是一个yield语句,因此方法的执行过程被挂起,而next方法返回值为yield关键字后面表达式的值,即为1。
当调用gen.send(2)方法时,python首先恢复MyGenerator方法的运行环境。同时,将表达式(yield 1)的返回值定义为send方法参数的值,即为2。这样,接下来value=(yield 1)这一赋值语句会将value的值置为2。继续运行会遇到yield value语句。因此,MyGenerator方法再次被挂起。同时,send方法的返回值为yield关键字后面表达式的值,也即value的值,为2。
当调用send(3)方法时MyGenerator方法的运行环境。同时,将表达式(yield value)的返回值定义为send方法参数的值,即为3。这样,接下来value=(yield value)这一赋值语句会将value的值置为3。继续运行,MyGenerator方法执行完毕,故而抛出StopIteration异常。
总的来说,send方法和next方法唯一的区别是在执行send方法会首先把上一次挂起的yield语句的返回值通过参数设定,从而实现与生成器方法的交互。但是需要注意,在一个生成器对象没有执行next方法之前,由于没有yield语句被挂起,所以执行send方法会报错。例如
gen = MyGenerator()
print gen.send(2)
上面代码的输出为
Traceback (most recent call last):
File "test.py", line 16, in <module>
print gen.send(2)
TypeError: can't send non-None value to a just-started generator
当然,下面的代码是可以接受的
gen = MyGenerator()
print gen.send(None)
因为当send方法的参数为None时,它与next方法完全等价。但是注意,虽然上面的代码可以接受,但是不规范。所以,在调用send方法之前,还是先调用一次next方法为好。
#coding=utf-8
import time
# def producer():
# ret=[]
# for i in range(10):
# time.sleep(0.1)
# ret.append("包子%s" %i)
# return ret
#
# def consumer(res):
# for index,baozi in enumerate(res):
# time.sleep(0.1)
# print("第%s个人,吃了%s"%(index,baozi))
#
# res=producer()
# consumer(res)
#要求:利用生成器将生产与消费同步进行,不是迭代生产完在让消费者进行消费【两个程序同时生产,第一个函数的生产值得出,之后交由第二个函数在执行】
#触发迭代器运行的操作send()函数,必须加参数
# def test1():
# print("开始啦!")
# first=yield 1
# print("第一次!",first)
# yield 2
# print("第二次!")
# t=test1() #只是拿到了生成器
# #g1=next(t) #返回第一个print
# #print(g1) #返回yield值
# #print(t.__next__()) #直接调作用next会直接执行到yield这一步(并且返回结果)
# #触发生成器的运行 t.send(None)必须传参数
# #t.send(None) 1、可以触发生成器向下执行,2、将值传给yield 在使用send之前必须是使用过next之后,不然会报错(不能将非NONE值发送给刚刚启动的生成器,当你传一个空值的时候,又会报错:必须要带一个参数)
# #print(t.__next__())
# s=t.send()
# print(s)
#send方法和next方法唯一的区别是在执行send方法会首先把上一次挂起的yield语句的返回值通过参数设定,从而实现与生成器方法的交互。但是需要注意,
#在一个生成器对象没有执行next方法之前,由于没有yield语句被挂起,所以执行send方法会报错。
#send方法有一个参数,该参数指定的是上一次被挂起的yield语句的返回值。
def consumer(name):
print("我是[%s],我准备开始吃包子了"%name)
while True:
baozi=yield
time.sleep(0.1)
print("%s 很开心的把[%s]吃掉了"%(name,baozi))
def producer():
c1=consumer('吴佩奇')
c2=consumer('王上山')
c1.__next__()
c2.__next__()
for i in range(10):
time.sleep(0.1)
c1.send("包子%s"%i)
c2.send("包子%s"%i)
producer()