Python 生成器与协程。yield是什么

351 阅读1分钟

生成器函数的一个特点就是走走停停,代码执行到了yield语句就停下来了,直到下一次调用,再从yield继续执行,这个特性可以应用在编写python协程。协程,顾名思义,协作编程,跟多线程的表现形式,目的一样,区别在协程只有一个线程,在一个线程中的不同函数间切换,可以减少切换线程的开销,也可减少多线程的不安全性。而灵活利用generator就可以做到协程。

next()和send()都是调用生成器的方法,区别在于send()可以传入参数,看个例子:

1  def consumer():
2     r = ''
3     while True:
4         n = yield r
5         if not n:
6             return
7         print('[CONSUMER] Consuming %s...' % n)
8         r = '200 OK'
9 
10 def produce(c):
11    c.send(None)
12    n = 0
13    while n < 5:
14        n = n + 1
15        print('[PRODUCER] Producing %s...' % n)
16        r = c.send(n)
17        print('[PRODUCER] Consumer return: %s' % r)
18    c.close()

c = consumer()
produce(c)

执行后的结果如下:

[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[PRODUCER] Consumer return: 200 OK

一步一步看,首先consumer()是个生成器函数,因为里面有yield,先把这个生成器函数对象赋值给c,然后调用produce函数,c作为参数。先执行第11行,c.send(None)等同于next(c),先让generator走起来,等到了第四行yield语句就停,目的是下次调用send()可以传入参数,下一段会讲解。接着producer从第12行开始执行,看到这是不是很像多线程的程序?

然后,producer的n变为1打印出来,再传给consumer,这时候producer调用了send(),切换到了consumer第四行,同时consumer的n给赋值了1,producer的r等待一个函数返回值。观察打印结果,该返回值为'200 OK',就是consumer里面的r值。我们来看看是怎么返回的这个r。

consumer的执行过程是4 -> 5 -> 7 -> 8 -> 3 -> 4。 可见,第8行'200 OK'赋值给r之后,第4行由yield r返回,返回值就是yield后面的值,yield就像是个暂停键。

总结一下,yield有两个作用。1:作为“暂停键”,将程序挂起。2:返回yield后面表达式的值,类似于lambda函数的值返回形式。

代码源:github.com/michaelliao…