Search code examples
pythonpython-3.xasynchronousasync-awaitbackwards-compatibility

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


Python 3.5 greatly expanded support for asynchronous programming with a new function definition syntax. Whereas async functions were previously just "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
    """

they now have their own special declaration syntax and special behavior by which they are no longer usable as usual generator functions:

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

This is not a question about the functional or practical differences between these types -- that is discussed in this StackOverflow answer.

My question is: why would I ever want to use async def? It seems like it provides no additional benefit over @asyncio.coroutine, but imposes an additional cost in that it

  1. breaks backward-compatibility (Python 3.5 code with async def won't even parse in older versions, although this is arguably a feature and not a bug) and
  2. seems to provide less flexibility in how the function can be called.

Solution

  • One possible answer is given by Martijn Pieters:

    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

    This has in fact come to fruition with new async with and async for syntax, which cannot be as easily implemented with a "tack-on" solution like a decorated generator.