Python 3, an Illustrated Tour Transcripts
Chapter: Asynchronous Programming
Lecture: asyncio Generators
Login or
purchase this course
to watch this video and the rest of the course contents.
0:01
In this video, we're going to talk about asynchronous generators. These are described in PEP 525 Python 3.6
0:07
in the PEP it describes some of the motivation for this we'll just read this because I think it's pretty interesting.
0:13
It says, however currently there is no equivalent concept for the asynchronous iteration protocol async for.
0:19
This makes writing asynchronous data producers unnecessarily complex as one must define a class that implements __aiter__ and __anext__
0:28
to be able to use it in async for statement. So we saw how to implement a asynchronous iterator
0:34
and we saw that you can do that by implementing __aiter__ and __anext__ if you've done that with normal iterators in Python,
0:41
you'll note that typically it's a lot easier to do that with the generator and this was the same motivation here.
0:47
Also interesting to notice this next paragraph that's in the pep. It says performance is an additional point for this proposal
0:52
in our testing of the reference implementation asynchronous generators are 2x faster than the equivalent implemented as an asynchronous iterator.
1:01
Kind of cool, you get some speed benefit and it's easier to write. So here's an example of the migration path. We are taking an asynchronous iterator
1:10
and we're starting to add a generator to it. Here I've got a class called GenRange,
1:15
and this is, again, similar to that Arange guy that we implemented before you can give it a start and an optional end
1:20
and if you don't specify the end it will use start as the end. And then we notice that we have down below specified __aiter__
1:28
and in there, note that we are yielding the results, we're just looping over range and yielding the result.
1:35
So we're combining a generator with an iterator. Here's an example of running this we can put it in a coroutine and because this is a coroutine itself
1:45
we need to put async in front of our for when we loop over it and this will print the numbers from 0 up to but not including 5.
1:52
Now we want to take that a step further we can do the same thing with normal iterators. We can yield from __iter__ in there,
2:00
but wouldn't it be nicer if we could just make a generator function that is a generator and we can do that, here we have a function that is a generator
2:07
because it has a yield in it but it also has an async in front of it. So this is a synchronous generator.
2:13
And this is the same implementation that we had before but note that the logic is a lot simpler and we don't have to keep track of state
2:21
because this freezes and comes back to itself like a normal generator in Python would,
2:26
so here's an example of using it, again because it is a coroutine it behaves as a coroutine when we loop over it
2:33
we need to put that async in front of our for there, but this will print the numbers from 0 up to but not including 5,
2:39
so that's how you can make a asynchronous genera tor in Python. Just put an async in front of your def there and include a yield in your logic
2:48
and you now have an asynchronous generator. Hopefully, you can use these to make your code more succinct and more legible.