python中终止协程和异常处理方式
作者:MZP_man 发布时间:2022-10-18 05:44:41
协程中未处理的异常会向上冒泡,传给 next 函数或 send 方法的调用方(即触发协程的对 象)。
下面示例举例说明如何使用之前博客示例中由装饰器定义的 averager 协程。
未处理的异常会导致协程终止
"""
预激协程的装饰器
"""
from inspect import getgeneratorstate
from functools import wraps
def coroutine(func):
"""装饰器:向前执行到第一个`yield`表达式,预激`func`"""
# 把被装饰的生成器函数替换成这里的 primer 函数;
# 调用 primer 函数时,返回预激后的 生成器。
@wraps(func)
def primer(*args, **kwargs):
# 调用被装饰的函数,获取生成器对象。
gen = func(*args, **kwargs)
# 预激生成器。
next(gen)
# 返回生成器。
return gen
return primer
@coroutine
def averager():
total = 0.0
count = 0
average = None
while True:
term = yield average
total += term
count += 1
average = total / count
if __name__ == '__main__':
coro_avg = averager()
# print(getgeneratorstate(coro_avg))
print(coro_avg.send(10))
print(coro_avg.send(30))
# 发送的值不是数字,导致协程内部有异常抛出。
print(coro_avg.send('spam'))
# 由于在协程内没有处理异常,协程会终止。
# 如果试图重新激活协程,会抛出 StopIteration 异常。
print(coro_avg.send(60))
上面示例,暗示了终止协程的一种方式:发送某个哨符值,让协程退出。内置的 None 和 Ellipsis 等常量经常用作哨符值。Ellipsis 的优点是,数据流中不太常有这个值。我还见 过有人把 StopIteration 类(类本身,而不是实例,也不抛出)作为哨符值;也就是说, 是像这样使用的:my_coro.send(StopIteration)。
从 Python 2.5 开始,客户代码可以在生成器对象上调用两个方法,显式地把异常发给协程。
这两个方法是 throw 和 close。
generator.throw(exc_type[, exc_value[, traceback]])
致使生成器在暂停的 yield 表达式处抛出指定的异常。
如果生成器处理了抛出的异常,代码会向前执行到下一个 yield 表达式,而产出的值会成为调用 generator.throw 方法 得到的返回值。
如果生成器没有处理抛出的异常,异常会向上冒泡,传到调用方的上下 文中。
generator.close()
致使生成器在暂停的yield 表达式处抛出GeneratorExit 异常。
如果生成器没有处 理这个异常,或者抛出了StopIteration 异常(通常是指运行到结尾),调用方不会 报错。
如果收到GeneratorExit 异常,生成器一定不能产出值,否则解释器会抛出 RuntimeError 异常。
生成器抛出的其他异常会向上冒泡,传给调用方。
下面举例说明
如何使用 close 和 throw 方法控制协程:
"""
学习在协程中处理异常的测试代码
"""
from inspect import getgeneratorstate
class DemoException(Exception):
"""为这次演示定义的异常类型。"""
def demo_exc_handling():
print('-> coroutine started')
try:
while True:
try:
x = yield
# 特别处理 DemoException 异常
except DemoException:
print('*** DemoException handled. Continuing...')
# 如果没有异常,那么显示接收到的值。
else:
print('-> coroutine received: {!r}'.format(x))
finally:
# 如果不管协程如何结束都想做些清理工作,
# 要把协程定义体中相关的代码放入try/ finally 块中
print('-> coroutine ending')
if __name__ == '__main__':
exc_coro = demo_exc_handling()
next(exc_coro)
exc_coro.send(11)
exc_coro.send(22)
# 激活和关闭 demo_exc_handling,没有异常
# exc_coro.close()
# 如果把 DemoException 异常传入 demo_exc_handling 协程,
# 它会处理,然后继续运行
# exc_coro.throw(DemoException)
# exc_coro.send(33)
# 如果无法处理传入的异常,协程会终止
exc_coro.throw(ZeroDivisionError)
print(getgeneratorstate(exc_coro))
来源:https://blog.csdn.net/MZP_man/article/details/100555806
猜你喜欢
- 本文实例讲述了PHP封装的PDO数据库操作类。分享给大家供大家参考,具体如下:<?phpclass DatabaseHandler {
- Oracle Tips, Tricks & Scripts1. Topic: Compiling Invalid Objects:O
- 下面代码即是VBScript代码在服务器端编译后的显示内容,如果我们把这段代码保存成静态文件(HTML)或JS文件,那么上一篇提出的问题就迎
- 今天开始学习 YUI,加强一下对 JavaScript 的理解。1. 命名空间 YAHOO
- 如果我需要在运行有SQL Server的机器上运行病毒扫描软件,怎样做才不会影响性能? 这取决于您希望运行的病毒扫描软件的类型。目前有三种类
- 1,jdk配置由于jdk官网的链接不直接支持wget,可以使用下面的方法下载jdk,其中jdk版本为jdk1.8.0_91:wget --n
- 1、RuntimeError: invalid argument 0: Sizes of tensors must match except
- 本文实例讲述了微信小程序学习笔记之表单提交与PHP后台数据交互处理。分享给大家供大家参考,具体如下:前面一篇结介绍了微信小程序函数定义、页面
- 几个月来好像就现在暂时无需求,稍微轻松一下,然后在Q群中发现有人提问,怎么用CSS实现数学公式“四又二分之一”。对于这个公式个人
- 内容摘要:通常的,ASP中表单提交的数据一般被写入数据库。然而,如果你想让发送数据更为简便易行,那么,可以将它书写为XML文件格式。这种方式
- 1. 获取时间1.1 当前时间获取package mainimport ( "
- 我们用Select的onchange事件时,常会遇到这样一个问题,那就是连续选相同一项时,不触发onchange事件.select的onch
- 许可和分发权限Access 2003 Developer Extensions随附的许可协议简化了解决方案或代码段的分发过程。这些协议包括免
- 可以不依靠DSN,但又可以在数据库连接字符串中指定驱动程序、服务器名字、数据库、数据库账号和密码吗?可以。在SQL Server 7,使用这
- map是key-value数据结构,又称为字段或者关联数组。类似其他编程语言的集合一、基本语法var 变量名 map[keyty
- 一、日期类型:对于SQL Server 2008 来说(因为2000甚至2005已经稍微有被淘汰的迹象,所以在此不作过多说明,加上自己工作使
- 一、检测它是不是整数function Is_Int(a_str) if&
- 为了让鼠标移到小图上显示大图,我利用鼠标事件新建了一个层来显示大图.当然之前最好得到XY坐标取得当前鼠标的X,Y坐标:function&nb
- 阅读:Chapter 3 * 的表格“Misquotations are the only quotations tha are never
- 代码如下:USE TestDB declare @conversation uniqueidentifier while exists (s