python 预激协程的装饰器

如果不预激,那么协程没什么用。调用 my_coro.send(x) 之前,记住一定要调用 next(my_ coro)。为了简化协程的用法,有时会使用一个预激装饰器。
示例如下:

from inspect import getgeneratorstate
from functools import wraps


def coroutine(func):
    """装饰器:向前执行到第一个`yield`表达式,预激`func`"""

    @wraps(func)
    def primer(*args, **kwargs):  # 把被装饰的生成器函数替换成这里的 primer 函数;调用 primer 函数时,返回预激后的 生成器
        gen = func(*args, **kwargs)  # 调用被装饰的函数,获取生成器对象。
        next(gen)  # 预激生成器。
        return gen  # 返回生成器。

    return primer


@coroutine  # 把装饰器应用到 averager 函数上
def averager():  # 实现求平均值
    total = 0.0
    count = 0
    average = None
    while True:
        term = yield average
        total += term
        count += 1
        average = total / count


if __name__ == '__main__':
    # 调用 averager() 函数创建一个生成器对象,在 coroutine 装饰器的 primer 函数中已经 预激了这个生成器。
    coro_avg = averager()
    # getgeneratorstate 函数指明,处于 GEN_SUSPENDED 状态,因此这个协程已经准备好,可以接收值了
    print(getgeneratorstate(coro_avg))  # GEN_SUSPENDED
    # 可以立即开始把值发给 coro_avg——这正是 coroutine 装饰器的目的。
    print(coro_avg.send(10))  # 10.0
    print(coro_avg.send(30))  # 20.0
    print(coro_avg.send(5))  # 15.0

这样就不用用next()进行激活协成了

很多框架都提供了处理协程特殊装饰器,不过不是所有装饰器都用于预激协程,有些会提供其他服务,例如勾入事件循环。比如说,异步网络库 Tornado 提供了 tornado.gen 装饰器(http://tornado.readthedocs.org/en/latest/gen.html

使用 yield from 句法调用协程时,会自动预激,因此与上面示例中的@coroutine 等装饰器不兼容。Python 3.4 标准库里的 asyncio.coroutine 装饰器不会预激协程,因此能兼容 yield from 句法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值