【python】关键字yield——生成器

Python 的关键字 yield 有哪些用法和用途?

yield 的用法有以下四种常见的情况:

  • 一个是生成器,
  • 二是用于定义上下文管理器,
  • 三是协程,
  • 四是配合 from 形成 yield from 用于消费子生成器并传递消息。

        这四种用法,其实都源于 yield 所具有的暂停的特性,也就说程序在运行到 yield 所在的位置 result = yield expr 时,先执行 yield expr 将产生的值返回给调用生成器的 caller,然后暂停,等待 caller 再次激活并恢复程序的执行。而根据恢复程序使用的方法不同,yield expr 表达式的结果值 result 也会跟着变化。如果使用 __next()__ 来调用,则 yield 表达式的值 result None;如果使用 send() 来调用,则 yield 表达式的值 result 是通过 send 函数传送的值。

我使用到的看代码中使用的是生成器,这里主要记录一下“生成器”的使用。其他使用方式参考:https://www.zhihu.com/question/345210030/answer/841903171


 

>>> def echo(value=None):
...     print("Begin...")
...     try:
...         while True:
...             try:
...                 value = (yield value)
...             except Exception as e:
...                 value = e
...     finally:
...         print("Clean up!!!")
...
>>> generator = echo(1)
>>> print(next(generator))
Begin...
1
>>> print(next(generator))
None
>>> print(generator.send(2))
2
>>> generator.throw(TypeError, "spam")
TypeError('spam')
>>> generator.close()
Clean up!!!

作者:wanwan yang
链接:https://www.zhihu.com/question/345210030/answer/841903171
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

上面这段代码的说明如下图所示:

preview

  1. 执行第一个 next(generator) 的时候,也就是预激活生成器,生成器开始执行,打印 Begin... 字符串,执行到 value = (yield value) 的位置时,首先调用 yield value 产生数字 1,然后生成器在 yield 的位置暂停。
  2. 接着调用第 2 个 next(generator) 的时候,生成器恢复执行,由于使用 next() 来调用生成器函数, value 的值会变成 None ,因此生成器函数继续执行到 yield value 时,会将 value 的值 None 返回给解释器,然后再次暂停。
  3. 接着使用 send(2) 方法继续调用生成器,value 接收到传入的数字 2,继续到执行 value = (yield value) ,将数字 2 返回给解释器后暂停。
  4. 此后,解释器再次通过 throw(TypeError, "spam") 方法调用,生成器恢复执行,并抛出异常,生成器捕获到异常,并将异常 TypeError('spam') 赋值给变量 value,然后程序再次执行到 value = (yield value) ,将 TypeError('spam') 返回给解释器。
  5. 最后,程序调用 close() 方法,在生成器函数的位置抛出 GeneratorExit ,异常被抛出,生成器正常退出,并最终执行最外层 try 语句对应的 finally 分支,打印输出 Clean up

生成器

不出意外,你最先遇到 yield 一定会是一个生成器函数里面。生成器是一个用于不断生成数字或者其他类型的值的函数,可以通过 for 循环或者 next() 函数逐一调用。这里需要强调的是,生成器包含的是一个没有赋值的 yield 表达式,所以下面两种形式是等价的:

def integers_1():
    for i in range(4):
        yield i + 1
def integers_2():
    for i in range(4):
        value = yield i + 1

 这里之所以强调第二种形式,是为了在理解通过 send() 方法发送 value 时,能够更好地理解 yield。同时,也能够更正确地说明,调用生成器返回的值是 yield 关键字右边的表达式 i + 1 的值,而不是 yield 表达式本身的结果值。

>>> for n in integers_1():
...     print(n)
...
1
2
3
4
>>> for n in integers_2():
...     print(n)
...
1
2
3
4

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值