Asynchronous Iteration and Asynchronous Generators
Learn about asynchronous iteration and asynchronous generators in Python.
We'll cover the following...
In the same way that we have the iterator objects (that is, objects that support being iterated over with Python's built-in for
loop), we can do the same, but in an asynchronous fashion.
The __anext__
and __aiter__
coroutines
Imagine we want to create an iterator to abstract the way in which we read data from an external source (like a database), but the part that extracts the data itself is a coroutine, so we couldn't call it during the already familiar __next__
operation as before. That's why we need to make use of the __anext__
coroutine.
The following example illustrates in a simple way how this can be achieved. Disregarding external dependencies, or any other accidental complexity, we'll focus on the methods that make this type of operation possible in order to study them:
import asyncioimport randomasync def coroutine():await asyncio.sleep(0.1)return random.randint(1, 10000)class RecordStreamer:def __init__(self, max_rows=100) -> None:self._current_row = 0self._max_rows = max_rowsdef __aiter__(self):return selfasync def __anext__(self):if self._current_row < self._max_rows:row = (self._current_row, await coroutine())self._current_row += 1return rowraise StopAsyncIteration
The first method, __aiter__
, is used to indicate that the object is an asynchronous iterator. Just like in the synchronous version, most of the time it's enough to return self
, and therefore it doesn't need to be a ...