python生成器中的send()方法和next()方法

在异步IO的使用时,generator是最基本的一个实现方法。python生成器有两个主要方法,一个是send一个是next。今天我们来看看两者的用法和联系。在每段代码中,第一个next调用,相当于启动生成器,会从生成器函数的第一行代码开始执行,直到第一次执行完yield语句(第4行)后,跳出生成器函数。然后第二个next调用,进入生成器函数后,从yield语句的下一句语句(第5行)开始执行,然后重新运行到yield语句,执行后,跳出生成器函数后面再次调用next,依次类推。

python生成器中的send()方法和next()方法

这里我们用经典的生产者-消费者模型举个例子(摘自廖雪峰的博客)

defconsumer():
r=0
foriinxrange(3):
yieldr
r='200OK'+str(i)
c=consumer()
n1=c.next()
n2=c.next()
n3=c.next()

实际上next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做c.next() 和 c.send(None) 作用是一样的。

第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有python yield语句来接收这个值。

相关推荐:《python教程》

下面说明下send执行的顺序。先记住,n1 = yield r这句话是从右往左执行的。当第一次send(None)(对应11行)时,启动生成器,从生成器函数的第一行代码开始执行,直到第一次执行完yield(对应第4行)后,跳出生成器函数。这个过程中,n1一直没有定义。

运行到send(1)时,进入生成器函数,此时,将yield r看做一个整体,赋值给它并且传回。此时即相当于把1赋值给n1,但是并不执行yield部分。下面继续从yield的下一语句继续执行,然后重新运行到yield语句,执行后,跳出生成器函数。即send和next相比,只是开始多了一次赋值的动作,其他运行流程是相同的。

defconsumer():
r='here'
whileTrue:
n1=yieldr#这里的等式右边相当于一个整体,接受回传值
ifnotn1:
return
print('[CONSUMER]Consuming%s...'%n1)
r='%d00OK'%n1
defproduce(c):
aa=c.send(None)
n=0
whilen<5:
n=n+1
print('[PRODUCER]Producing%s...'%n)
r1=c.send(n)
print('[PRODUCER]Consumerreturn:%s'%r1)
c.close()
c=consumer()
produce(c)

运行结果:

[PRODUCER]Producing1...
[CONSUMER]Consuming1...
[PRODUCER]Consumerreturn:100OK
[PRODUCER]Producing2...
[CONSUMER]Consuming2...
[PRODUCER]Consumerreturn:200OK
[PRODUCER]Producing3...
[CONSUMER]Consuming3...
[PRODUCER]Consumerreturn:300OK
[PRODUCER]Producing4...
[CONSUMER]Consuming4...
[PRODUCER]Consumerreturn:400OK
[PRODUCER]Producing5...
[CONSUMER]Consuming5...
[PRODUCER]Consumerreturn:500OK