Many Python programmers already know and love generators,
because they're a super convenient way to write your own iterators
that you can loop over using for
. Python 3.6 added a new thing:
async generators. Just
like regular generators, they're super convenient; the difference is
that now you loop over them using async for
, and this means you
can use await
inside them. If you're not doing async programming,
you probably don't care about this at all. But if you are doing
async programming, this is super awesome. If you're not convinced,
check out this 5-minute demo (warning: contains
Nathaniel's first ever attempt to live-code on stage).
But what if you aren't using the latest and greatest Python, but still
want that async generator goodness? That's where this package comes
in. It gives you async generators and @asynccontextmanager
on
Python 3.5+.
Example 1: suppose you want to write your own async generator. The goal is that you can use it like:
async for json_obj in load_json_lines(stream_reader):
...
If you're using Python 3.6+, you could implement load_json_lines using native syntax:
async def load_json_lines(stream_reader):
async for line in stream_reader:
yield json.loads(line)
Or, you could use async_generator
, and now your code will work on
Python 3.5+:
from async_generator import async_generator, yield_
@async_generator
async def load_json_lines(stream_reader):
async for line in stream_reader:
await yield_(json.loads(line))
Example 2: let's say you want to write your own async context manager. The goal is to be able to write:
async with background_server() as ...:
...
If you're using Python 3.7+, you don't need this library; you can write something like:
from contextlib import asynccontextmanager
@asynccontextmanager
async def background_server():
async with trio.open_nursery() as nursery:
value = await nursery.start(my_server)
try:
yield value
finally:
# Kill the server when the scope exits
nursery.cancel_scope.cancel()
This is the same, but works on 3.5+:
from async_generator import async_generator, yield_, asynccontextmanager
@asynccontextmanager
@async_generator
async def background_server():
async with trio.open_nursery() as nursery:
value = await nursery.start(my_server)
try:
await yield_(value)
finally:
# Kill the server when the scope exits
nursery.cancel_scope.cancel()
(And if you're on 3.6, so you have built-in async generators but no
built-in @asynccontextmanager
, then don't worry, you can use
async_generator.asynccontextmanager
on native async generators.)
- Install:
python3 -m pip install -U async_generator
(or on Windows, maybepy -3 -m pip install -U async_generator
- Manual: https://async-generator.readthedocs.io/
- Bug tracker and source code: https://github.com/python-trio/async_generator
- Real-time chat: https://gitter.im/python-trio/general
- License: MIT or Apache 2, your choice
- Contributor guide: https://trio.readthedocs.io/en/latest/contributing.html
- Code of conduct: Contributors are requested to follow our code of conduct in all project spaces.
Trio is a new async concurrency
library for Python that's obsessed with usability and correctness – we
want to make it easy to get things right. The async_generator
library is maintained by the Trio project as part of that mission, and
because Trio uses async_generator
internally.
You can use async_generator
with any async library. It works great
with asyncio
, or Twisted, or whatever you like. (But we think Trio
is pretty sweet.)