Python 3, an Illustrated Tour Transcripts
Chapter: Asynchronous Programming
Lecture: asyncio Generators
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.