8.11. Async-iterators

Een async-iterator is de asyncio-versie van een iterator. Het Python-overzicht introduceerde het synchrone iteratorprotocol – __iter__ en __next__ – en de for-lus die het aandrijft. Async-iterators voegen aan elke stap een await toe, zodat de iterator kan wachten tussen waarden door zonder de event loop te blokkeren.

8.11.1. Het protocol

Een klasse is een async-iterator wanneer deze het volgende implementeert

  • __aiter__(self) – geeft het iteratorobject terug, doorgaans self.

  • async def __anext__(self) – geeft de volgende waarde terug, of werpt StopAsyncIteration op wanneer er geen meer zijn.

De bijbehorende lusconstructie is async for

import asyncio


class FrameCounter:
    """Yield N integers, one per frame period."""

    def __init__(self, n, period_ms):
        self._n = n
        self._period_ms = period_ms
        self._i = 0

    def __aiter__(self):
        return self

    async def __anext__(self):
        if self._i >= self._n:
            raise StopAsyncIteration
        await asyncio.sleep_ms(self._period_ms)
        self._i += 1
        return self._i

async def main():
    async for n in FrameCounter(5, 200):
        print(n)

De async for-lus wacht (await) op elke aanroep van __anext__, zodat de coroutine die de lus uitvoert tussen waarden door de controle teruggeeft aan de event loop, net als bij elke andere await.

8.11.2. Wanneer je het inzet

Telkens wanneer de applicatie een gegevensbron heeft die in de loop van de tijd binnenkomt en de consument deze lui (lazy) moet doorlopen. Een sensor die per periode een meetwaarde produceert, een netwerksocket die berichten aflevert, een framegenerator – overal waar de vorm while True: x = await source.next(); process(x) past, is async for x in source de nettere schrijfwijze.

Voor bronnen die uitzenden tot een eindige eindvoorwaarde werpt de iterator StopAsyncIteration op en eindigt async for normaal. Voor bronnen die nooit eindigen – een continue sensorstroom, een langlopend abonnement – loopt de lus totdat de coroutine waarin deze leeft wordt geannuleerd of de bijbehorende taak wordt afgebroken.