本节内容
1、概述
2、生成器执行原理
3、send()和__next__()方法的区别
4、yield实现并行效果
一、概述
之前只是介绍生成器,那有些同学就说了,这个生成器除了能节省资源,提高工作效率,但是我们再哪些场景下可以用呢?在哪些地方可以体现出它的价值呢?下面我们来逐一解答这些疑问。
二、生成器执行原理
1、执行原理
1
2
3
4
5
6
7
8
9
10
11
12
13
|
def consumer(name):
print ( "%s 准备吃包子啦!" % name)
while True :
baozi = yield
print ( "包子[%s]来了,被[%s]吃了" % (baozi,name))
c = consumer( "zhangqigao" )
c.__next__() #输出 zhangqigao 准备吃包子啦! |
如果我再加一个__next__()方法会有什么效果?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
def consumer(name):
print ( "%s 准备吃包子啦!" % name)
while True :
baozi = yield
print ( "包子[%s]来了,被[%s]吃了" % (baozi,name))
c = consumer( "zhangqigao" )
c.__next__() c.__next__() #输出 zhangqigao 准备吃包子啦! 包子[ None ]来了,被[zhangqigao]吃了
|
很明显,第一种情况没有执行"print("包子[%s]来了,被[%s]吃了"%(baozi,name))",这段代码,接下来我们就来调试一下。
2、调试
第一步:生成一个生成器
第二步:执行第一个__next__()方法进入函数,执行到yield时中断,把返回值返回给baozi这个变量:
第三步:开始执行下面的程序,也就执行到了第二个__next__()方法,直接跳转到yield这边,继续上一次的中断往下执行,这样就执行了yield下面的程序,当再次执行到yield关键字时,则继续中断,并且把返回值赋给baozi关键字,如果下面没有其他程序,则程序结束。
小结:
- 用yield做生成器,你想把什么返回到外面,你就把yield关键字放在那里。
- yield其实是保留了函数的中断状态,返回当前的值。
- 如果yield没有返回值,就返回一个空值None
三、send()和__next__()方法的区别
1、send()方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
def consumer(name):
print ( "%s 准备吃包子啦!" % name)
while True :
baozi = yield
print ( "包子[%s]来了,被[%s]吃了" % (baozi,name))
c = consumer( "zhangqigao" )
c.__next__() #不使用__next__()方法会报错
b1 = "肉松馅"
c.send(b1) #调用yield,同时给yield传一个值
b2 = "韭菜馅"
c.send(b2) #输出 zhangqigao 准备吃包子啦! 包子[肉松馅]来了,被[zhangqigao]吃了 包子[韭菜馅]来了,被[zhangqigao]吃了 |
从上面可以看出send()和__next__()方法的区别:
- __next__()只是调用这个yield,也可以说成是唤醒yield,但是不不会给yield传值。
- send()调用这个yield或者说唤醒yield同时,也活给yield传一个值。
- 使用send()函数之前必须使用__next__(),因为先要中断,当第二次调用时,才可传值。
为什么给消费者传值时,必须先执行__next__()方法?
因为如果不执行一个__next__()方法,只是把函数变成一个生成器,你只有__next__()一下,才能走到第一个yield,然后就返回了,调用下一个send()传值时,才会发包子。
四、yield实现并行效果
yield还有一个更强大的功能,就是:单线程实现并发效果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import time
def consumer(name):
print ( "%s 准备吃包子啦!" % name)
while True :
baozi = yield
print ( "包子[%s]来了,被[%s]吃了" % (baozi,name))
def producer(name):
c = consumer( "A" )
c2 = consumer( "B" )
c.__next__()
c2.__next__()
print ( "老子准备吃包子啦!" )
for i in range ( 10 ):
time.sleep( 1 )
print ( "做了一个包子,分两半" )
c.send(i)
c2.send(i)
producer( "zhangqigao" )
|
这个是生产者消费者模式,这个也就是后面协程的效果,这个我们后续再讲,先了解一下,生成器可以实现并发效果,极大的提高程序的运行效率。