python中终止协程和异常处理方式

 更新时间:2022年12月16日 16:16:26   作者:MZP_man  
这篇文章主要介绍了python中终止协程和异常处理方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

协程中未处理的异常会向上冒泡,传给 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))

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 对Python 窗体(tkinter)树状数据(Treeview)详解

    对Python 窗体(tkinter)树状数据(Treeview)详解

    今天小编就为大家分享一篇对Python 窗体(tkinter)树状数据(Treeview)详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-10-10
  • 使用OpenCV获取图片连通域数量,并用不同颜色标记函

    使用OpenCV获取图片连通域数量,并用不同颜色标记函

    这篇文章主要介绍了使用OpenCV获取图片连通域数量,并用不同颜色标记函,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-06-06
  • numpy 对矩阵中Nan的处理:采用平均值的方法

    numpy 对矩阵中Nan的处理:采用平均值的方法

    今天小编就为大家分享一篇numpy 对矩阵中Nan的处理:采用平均值的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-10-10
  • python使用 zip 同时迭代多个序列示例

    python使用 zip 同时迭代多个序列示例

    这篇文章主要介绍了python使用 zip 同时迭代多个序列,结合实例形式分析了Python使用zip遍历迭代长度相等与不等的序列相关操作技巧,需要的朋友可以参考下
    2019-07-07
  • Python Flask异步发送邮件实现方法解析

    Python Flask异步发送邮件实现方法解析

    这篇文章主要介绍了Python Flask异步发送邮件实现方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • Python爬取网易云音乐上评论火爆的歌曲

    Python爬取网易云音乐上评论火爆的歌曲

    最近跟着网上教程学着用python爬取问题,于是就想试着扒一扒Python爬取网易云音乐上评论火爆的歌曲,下面这篇文章就主要介绍了利用Python如何爬取网易云音乐上那些评论火爆的歌曲,需要的朋友可以参考借鉴,一起来看看吧。
    2017-01-01
  • python基于pygame实现飞机大作战小游戏

    python基于pygame实现飞机大作战小游戏

    这篇文章主要为大家详细介绍了python基于pygame实现飞机大作战小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • python获得一个月有多少天的方法

    python获得一个月有多少天的方法

    这篇文章主要介绍了python获得一个月有多少天的方法,涉及Python中datetime模块操作日期的相关技巧,需要的朋友可以参考下
    2015-06-06
  • python 使用事件对象asyncio.Event来同步协程的操作

    python 使用事件对象asyncio.Event来同步协程的操作

    这篇文章主要介绍了python 使用事件对象asyncio.Event来同步协程的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-05-05
  • 利用Python脚本批量生成SQL语句

    利用Python脚本批量生成SQL语句

    这篇文章主要介绍了利用Python脚本批量生成SQL语句,具有很好对参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03

最新评论