关键字yield学习
实例
- python中有一个非常有用的语法叫做生成器,所利用到的关键字就是yield。有效利用生成器这个工具可以有效地节约系统资源,避免不必要的内存占用。
- 只要出现了yield表达式(Yield expression),那么事实上定义的是一个generator function。
生成器
def fun():
print("*start*"*2)
for i in range(20):
x=yield i
print('good',x)
if __name__ == '__main__':
a=fun()
print(a.__next__())
print(a.__next__())
输出结果
*start**start*
0
good None
1
流程解释
- 程序开始执行以后,因为fun函数中有yield关键字,所以fun函数并不会真的执行,而是先得到一个生成器g(相当于一个对象)
- 直到调用next方法,fun函数正式开始执行,先执行fun函数中的print方法,然后进入for循环
- 程序遇到yield关键字,然后把yield想想成return,return了一个i之后,程序停止,并没有执行赋值给x操作,此时a.next()语句执行完成,所以输出的前两行
- 又开始执行下面的print(a.next()),这个时候和上面那个差不多,不过不同的是,这个时候是从刚才那个next程序停止的地方开始执行的,也就是要执行x的赋值操作,这时候要注意,这个时候赋值操作的右边是没有值的(因为刚才那个是return出去了,并没有给赋值操作的左边传参数),所以这个时候x赋值是None,所以接着下面的输出就是x:None,
协程
- 从句法上看,协程与生成器类似,都是定义体中包含 yield 关键字的函数。可是,在协程中, yield 通常出现在表达式的右边(例如, datum = yield),可以产出值,也可以不产出 —— 如果 yield 关键字后面没有表达式,那么生成器产出 None。
- 协程可能会从调用方接收数据,不过调用方把数据提供给协程使用的是 .send(datum) 方法,而不是next(…) 函数。
def fun():
print("*start*"*2)
for i in range(20):
x=yield i
print('good',x)
if __name__ == '__main__':
a=fun()
print(a.__next__())
print(a.send(5))
print(a.__next__())
a.send(6)
输出结果
*start**start*
0
good 5
1
good None
2
good 6
流程解释
- 先执行a.next(),x为none
- 程序执行a.send(5),a.send(5)是发送一个参数5给x, x为5.程序会从yield关键字那一行继续向下运行,所以程序会继续向下运行执行print方法,打印了good 5。
- 由于send方法中包含next()方法,然后执行next的作用,再次进入for循环,遇见下一回的yield,打印了1
- 遇到第二个a.next()时,接着上一个next()方法停止的地方开始执行也就是yield处,由于没有send所以x为none,先打印2,再打印good none
- 同理再次执行send程序执行再次遇到yield关键字,yield会返回后面的值后,程序再次暂停,直到再次调用next方法或send方法。