@asyncio.coroutine 与 async def

新手上路,请多包涵

有了我见过的 asyncio 库,

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

async def function():
    ...

互换使用。

两者之间有什么功能上的区别吗?

原文由 Jason 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 650
2 个回答

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

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

  1. 机协程 对象不实现 __iter____next__ 方法。因此,它们不能迭代或传递给 iter()list()tuple() 和其他内置函数。它们也不能在 for..in 循环中使用。

尝试在原生协程对象上使用 __iter____next__ 将导致 TypeError 。

  1. 普通生成器 不能 yield from _本机协程_:这样做会导致 TypeError 。

  2. _基于生成器的协程_(对于 asyncio 代码必须用 @asyncio.coroutine )可以 yield from _本机协程对象_。

  3. inspect.isgenerator()inspect.isgeneratorfunction() 返回 False 用于 本机协程 对象和 _本机协程函数_。

上面的第 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_ITER vs GET_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? 更深入地涵盖了这种差异。

原文由 Zero Piraeus 发布,翻译遵循 CC BY-SA 3.0 许可协议

async def 是 Python 3.5 的新语法。 You could use await , async with and async for inside async def s.

@coroutine is a functional analogue for async def but it works in Python 3.4+ and yield from construction instead of await .

从实用的角度来看,如果您的 Python 是 3.5+,则永远不要使用 @coroutine

原文由 Andrew Svetlov 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题