python - @asyncio.coroutine 与 async def

标签 python python-3.x async-await python-3.5 python-asyncio

使用我见过的 asyncio 库,

@asyncio.coroutine
def function():
    ...

async def function():
    ...

可以互换使用。

两者在功能上有区别吗?

最佳答案

是的,使用 async def 语法的原生协程和使用 asyncio.coroutine 装饰器的基于生成器的协程之间存在功能差异。

根据PEP 492 ,其中引入了 async def 语法:

  1. Native coroutine objects do not implement __iter__ and __next__ methods. Therefore, they cannot be iterated over or passed to iter(), list(), tuple() and other built-ins. They also cannot be used in a for..in loop.

    An attempt to use __iter__ or __next__ on a native coroutine object will result in a TypeError .

  2. Plain generators cannot yield from native coroutines: doing so will result in a TypeError .

  3. generator-based coroutines (for asyncio code must be decorated with @asyncio.coroutine) can yield from native coroutine objects.

  4. inspect.isgenerator() and inspect.isgeneratorfunction() return False for native coroutine objects and native coroutine functions.

上面的第 1 点意味着虽然使用 @asyncio.coroutine 装饰器语法定义的协程函数可以像传统的生成器函数一样运行,但使用 async def 语法定义的协程函数则不能。

这里有两个最小的,表面上等效的协程函数,用两种语法定义:

import asyncio

@asyncio.coroutine
def decorated(x):
    yield from x 

async def native(x):
    await x 

虽然这两个函数的字节码几乎相同:

>>> import dis
>>> dis.dis(decorated)
  5           0 LOAD_FAST                0 (x)
              3 GET_YIELD_FROM_ITER
              4 LOAD_CONST               0 (None)
              7 YIELD_FROM
              8 POP_TOP
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE
>>> dis.dis(native)
  8           0 LOAD_FAST                0 (x)
              3 GET_AWAITABLE
              4 LOAD_CONST               0 (None)
              7 YIELD_FROM
              8 POP_TOP
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE

...唯一的区别是 GET_YIELD_FROM_ITERGET_AWAITABLE,当尝试迭代它们返回的对象时,它们的行为完全不同:

>>> list(decorated('foo'))
['f', 'o', 'o']

>>> list(native('foo'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'coroutine' object is not iterable

显然 'foo' 不是可等待的,因此尝试用它调用 native() 没有多大意义,但希望这一点很清楚它返回的 coroutine 对象是不可迭代的,不管它的参数是什么。

Brett Cannon 对 async/await 语法的更详细调查:How the heck does async/await work in Python 3.5?更深入地涵盖了这种差异。

关于python - @asyncio.coroutine 与 async def,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40571786/

相关文章:

Python 3 map 返回 NoneType 对象列表而不是我修改的类型?

Python Kivy 并将本地照片添加到 Carousel

c# - 是否有等同于 : Storagefile. Openasync 的 .NET 4.5

javascript - 我的函数声明中哪一个更好?生成器还是异步/等待?

javascript - JS Async/Await vs Promise vs Callbacks

Python/Numba - 自定义类对象作为输入类型

python - 我怎样才能打印一些东西,然后在同一行调用带有打印的函数?

python - 使用霍夫圈读取骰子的点

python - 播放mp3原始音频数据而无需写入文件

python - "TypeError: Input ' global_step ' of ' ResourceApplyAdagradDA ' Op has type int32 that does not match expected type of int64."这是什么错误?