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


猜你喜欢
- 一、概念介绍嵴线图(ridgeline plot),用来展示同一维度的几个数据的分布情况,每一层嵴线(峰峦)都是一个直方图或者密度图,层层堆
- 在python自动化中,经常会遇到对数据文件的操作,比如添加多名员工,但是直接将员工数据写在python文件中,不但工作量大,要是以后再次遇
- 一个等号是赋值操作,==先转换类型再比较,===先判断类型,如果不是同一类型直接为false。=== 判断规则如果类型不同,就[不相等]&n
- DFA 算法是通过提前构造出一个 树状查找结构,之后根据输入在该树状结构中就可以进行非常高效的查找。设我们有一个敏感词库,词酷中的词汇为:我
- 最近做的一个项目对日期时间的处理比较多,最后整理到一个工具类里面,方便以后使用:1. 在utils文件夹下新建一个dateTimeUtil.
- 公共的抽象基类import numpy as npfrom abc import ABCMeta, abstractmethodclass
- 电脑安装git客户端、注册github账号并登陆到本地项目文件夹右键选择git bash here输入个人信息(代码提交者)git conf
- 引文: 长期以来,多媒体信息在计算机中都是以文件形式存放,由操作系统管理的,但是随着计算机网络,分布式计算的发展,对多媒体信息进行高效的管理
- 目录一、Go调用C代码的原理二、在Go中使用C语言的类型1、原生类型数值类型指针类型字符串类型数组类型2、自定义类型枚举(enum)结构体(
- 该代码用的是paramiko模块,python版本是python2.7下面上源码# -*- coding: utf-8 -*-import
- 复数数据结构在 cpython 当中对于复数的数据结构实现如下所示:typedef struct { double
- 这篇文章主要介绍了简单了解Python读取大文件代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 正在看的ORACLE教程是:Oracle数据库集复制方法浅议。前言 日益增长的分布式应用需求要求实现更好分布式的软件环境,不断推动着分布式技
- 最简单的CGO程序//cgo.gopackage mainimport "C"func main(){ &nb
- 在 * 站中,用户每次请求一个页面,服务器都会执行以下操作:查询数据库,渲染模板,执行业务逻辑,最后生成用户可查看的页面。这会消耗大量的资源
- 前言:看似简单的任务,往往隐藏陷阱!一个常见的任务是在一个列表上迭代,并根据条件删除一些元素。本文将展示如何完成该任务的不同方法,同时展示一
- 1. Python字典的clear()方法(删除字典内所有元素)#!/usr/bin/python# -*- coding: UTF-8 -
- python版本:3.8class object: """ The most base type "
- 北京时间2月15日据国外媒体报道,美国知名sns网站Facebook全球活跃用户量已突破1.75亿大关。数据显示,全球20%的网民都使用Fa
- 写SQL语句的时候很多时候会用到filter筛选掉一些记录,SQL对筛选条件简称:SARG(search argument/SARG) wh