为什么我们需要 asyncio.coroutine 装饰器?

问题描述 投票:0回答:2

为什么我们需要

asyncio.coroutine
装饰器?它提供什么功能?

例如:

# import asyncio
# @asyncio.coroutine
def gen():
    value = yield("Started")
    print(value)

a = gen()
a.send(None)
a.send("Done")

现在,如果我取消注释前两行并使用

asyncio.coroutine
装饰器,我仍然会得到相同的输出。

我的意思是这已经是一个

coroutine
- 一个可以暂停并通过参数传入的函数。为什么我需要用另一个
coroutine
来装饰它,即
asyncio.coroutine

python python-asyncio coroutine
2个回答
10
投票

重要的是要了解 生成器

asyncio
协程 - 是不同的东西。协程是使用生成器实现的,但(理论上)可以在没有生成器的情况下实现。生成器 - 是协程实现的一部分。

由于

asyncio
协程是使用生成器实现的,因此有时可以使用生成器作为协程而不会出现错误:

import asyncio


def main():
    yield from asyncio.sleep(1)
    print('done')


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

结果:

done

但它并不适用于所有类型的协程:

import asyncio


def main():
    # yield from asyncio.sleep(1)
    print('done')


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

结果:

TypeError: An asyncio.Future, a coroutine or an awaitable is required

这就是为什么(除了其他的东西)

asyncio.coroutine
装饰器使用:

import asyncio


@asyncio.coroutine
def main():
    # yield from asyncio.sleep(1)
    print('done')


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

结果:

done

但正如大家已经指出的那样,今天它实际上并不重要:因为 Python 3.5 装饰器和

yield from
已被关键字
async def
await
取代,这不仅更好,而且有助于将协程与其实现细节分开一个更好的方法。

import asyncio


async def main():
    # await asyncio.sleep(1)
    print('done')


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

0
投票

我参加这个聚会超级晚了,但从历史的角度来看,我对这个装饰者所做的事情很感兴趣。

接受的答案根本就是错误的,或者实际上是不合逻辑的,编辑它将是整个重写,所以最好将其留下并单独回答。

对于 OP 示例,

@asyncio.coroutine
所做的是将
CO_ITERABLE_COROUTINE
标志附加到对象的
co_flags
。这使得生成器可以与
await
关键字一起使用,也可以用于
yield from
本身不是生成器派生的“纯”协程。

# Check if 'func' is a generator function.
# (0x20 == CO_GENERATOR)
if co_flags & 0x20:
  # TODO: Implement this in C.
  co = func.__code__
  func.__code__ = CodeType(
    co.co_argcount, co.co_posonlyargcount, co.co_kwonlyargcount, co.co_nlocals,
    co.co_stacksize,
    co.co_flags | 0x100,  # 0x100 == CO_ITERABLE_COROUTINE
    co.co_code,
    co.co_consts, co.co_names, co.co_varnames, co.co_filename,
    co.co_name, co.co_firstlineno, co.co_lnotab, co.co_freevars,
    co.co_cellvars)
  return func

装饰器还有一些其他用途,特别是(如已接受的答案中所示),如果它还不是生成器,它会将常规函数转换为协程。

© www.soinside.com 2019 - 2024. All rights reserved.