Python 3, an Illustrated Tour Transcripts
Chapter: Asynchronous Programming
Lecture: Walk-through: Asyncio Context Iterators
Login or
purchase this course
to watch this video and the rest of the course contents.
0:00
In this video, we're going to look at async iter test, open that up in your editor. The first part says write an asynchronous iterator countdown
0:07
that accepts a count and a delay, when looped over asynchronously, it returns the numbers from count down to and including zero.
0:15
It waits for delay seconds before returning the next value. Okay, so we need to define a class called count down
0:23
and it needs to have a constructor that has a count and a delay so def __init__ and it needs to have a count and a delay in here
0:36
self.count is equal to count and self.delay is equal to delay. Okay, we need to implement this asynchronous iteration protocol.
0:46
So the first one is def __aiter__, and this can be defined as asynchronous or not, it just depends on whether you want to do an asynchronous call
0:57
in this case, I don't want to, I'm just going to return self and make this a self iterating coroutine.
1:03
Now, I need to define a __anext__ and this does need to be an async call so def __anext__.
1:20
Okay, there's a __anext__ and inside of here, we want to return count and then delay after each count.
1:29
So we need to have some little logic there to say something like, maybe I need to come up here and keep track of the value
1:35
that I'm going to return next. I'm going to say self.value is equal to count, value is what I'm going to return.
1:41
If self.val is equal to self.count, then let's just return self.val. So the first time we don't want to delay before we return the value,
1:55
so we want to say 10 and then wait for a second or whatever and then say 9 and then wait for a second and keep going that way.
2:01
Now, in this case, if self.val what we're going to return is equal to 0, we also want to return self.val
2:21
and otherwise, we want to say we want to sleep for delay and decrement our self.val. So we want to say await asyncio.sleep for self.delay
2:38
and then we want to return self.val and we're going to say self.val minus equals 1 and return self.val.
2:58
Okay, let's try this see if it works here. I'm going to say run async test, it thinks for a minute here and I get an error on line 43.
3:14
So that's this guy right here, I got an assertion error, so down here we're basically unrolling this protocol here.
3:21
We're saying get the aiter and then get a start time and call next on it and the first value since we passed in 2 should be 2
3:31
and assert the time is less than half a second since we're saying delay of 1 and then we're getting the next and saying that
3:40
the next value should be 1 and we got the next value was 2 instead of 1, so let's go up here and look at our logic here.
3:48
So the first time we returned self.val we didn't do anything, so our self.val is just going to still be self.val.
3:58
So maybe I want to say something like this like val is equal to self.val and if val is equal to self.count, return val.
4:09
And at this point we're going to say self.val minus equals 1 up here. And let's see if that works a little bit better.
4:25
So in the first case, we'll say val is equal to self.val which should be the start value.
4:32
We're going to decrement our instance member which shouldn't affect val and then if we're starting we're just going to return,
4:39
if we're at the end we're going to return. I think this is wrong, we don't want to return at the end,
4:45
we want to sleep before that, so we'll just get rid of that and we'll say if val is less than 0 then we want to raise a stop async iteration.
5:05
So that says we are done once we get 0 so don't do any more sleeping or whatever. Let's run this and see if it works.
5:18
Okay, I got an asyncio is not defined here. I better fix that and make it defined, import asyncio, let's run it again.
5:35
And it looks like it worked that time. So it passed, note that it took 2 seconds to run, or a little bit more than 2 seconds,
5:41
which makes sense because I said I want to count down from 2 and I want to have a one second delay in between there.
5:48
So it should give me 2, wait for one second, give me 1, wait for a second, give me 0 and not wait after that.
5:54
Note that the test here, we keep calling next and we assert it, it raises that stop async iteration error. So this is a little bit trickier.
6:05
There's some logic in here that you've got to sort of figure out but once you've got it, you can see that you have a little asynchronous counter
6:13
that will count down and sleep in there. Again, note that this __anext__, this is a coroutine
6:21
and because it's defined with async we can call await in there. This gives anything else on the event loop that wants to run
6:28
a chance to run at that point in time.