为什么我会想在 `@asyncio.coroutine` 上使用 `async def`?

Why would I ever want to use `async def` over `@asyncio.coroutine`?

Python 3.5 使用新的函数定义语法极大地扩展了对异步编程的支持。而异步函数以前只是 "generators with benefits":

def generate_numbers():
    """
    Generator function that lazily returns 1 - 100
    """
    for i in range 100:
        yield i

generate_async = asyncio.coroutine(generate_numbers)
generate_async.__doc__ = """
    Coroutine that lazily returns 1 - 100
    This can be used interchangeably as a generator or a coroutine
    """

它们现在有自己的特殊声明语法和特殊行为,它们不再像往常一样使用生成器函数:

aysnc def generate_async_native():
    """
    A coroutine that returns 1 - 100
    This CANNOT be used as a generator, and can ONLY be executed by running it from an event loop
    """
    for i in range(100):
        await i

这是而不是关于这些类型之间的功能或实际差异的问题——在中讨论.

我的问题是:我为什么要使用 async def?与 @asyncio.coroutine 相比,它似乎没有提供额外的好处,但会增加额外的成本,因为它

  1. 打破了向后兼容性(Python 3.5 代码与 async def 在旧版本中甚至不会 parse,尽管这可以说是一个功能而不是错误)和
  2. 似乎在调用函数方面提供的灵活性较低。

给出了一个可能的答案:

The advantages are that with native support, you can also introduce additional syntax to support asynchronous context managers and iterators. Entering and exiting a context manager, or looping over an iterator then can become more points in your co-routine that signal that other code can run instead because something is waiting again

这实际上已经通过新的 async withasync for 语法实现了,这不能像装饰生成器那样使用 "tack-on" 解决方案那么容易实现。