8.12. Asinkroni upravitelji konteksta

Pregled Pythona predstavio je upravitelje konteksta – objekte kojima upravljaju with blokovi, gdje se __enter__ izvršava na ulasku, a __exit__ na izlasku, bez obzira na to kako blok završi. Asinkroni upravitelji konteksta ista su zamisao prenesena u asyncio: __aenter__ i __aexit__ su korutine, pa postavljanje ili čišćenje mogu nešto awaitati. Blok koji njima upravlja je async with.

Jednog smo već koristili. asyncio.Lock je asinkroni upravitelj konteksta; stranica brave ga je koristila kao async with bus_lock: .... Ova stranica govori o pisanju jednog za vlastiti resurs aplikacije.

8.12.1. Kada napisati svoj

Kad aplikacija ima resurs kojem je potrebno upareno postavljanje i raščišćavanje, a barem jedna od tih strana mora nešto awaitati. Mrežne veze, senzori kojima je potrebna odgoda za smirivanje nakon konfiguracije, sve što nešto zaključa pri ulasku i otključa pri izlasku. Obični sinkroni oblik with ne primjenjuje se jer njegovi __enter__ i __exit__ ne mogu biti korutine.

8.12.2. Dvije metode

  • async def __aenter__(self) izvršava se kad se uđe u blok. Što god vrati, to je ono na što se veže neobavezna klauzula as name od async with. Vraćanje self je najčešći oblik, ali svaka vrijednost je u redu.

  • async def __aexit__(self, exc_type, exc, tb) izvršava se kad se izađe iz bloka. exc_type je None pri normalnom izlasku; pri iznimci (ili otkazivanju) to je klasa iznimke, a exc je instanca. Vraćanje vrijednosti koja je istinita govori Pythonu da je iznimka obrađena i da se ne treba propagirati. Vraćanje None (uobičajen slučaj) pušta iznimku da nastavi uz lanac poziva nakon što se čišćenje izvrši.

8.12.3. Razrađen primjer

Omotač reflektora koji uključuje LED-icu za tijelo bloka, s kratkom odgodom za smirivanje kako bi osvjetljenje bilo stabilno prije nego što se ikakvo snimanje dogodi, te ponovno isključuje LED-icu na izlasku:

import asyncio
from machine import LED


class Spotlight:
    def __init__(self, led):
        self._led = led

    async def __aenter__(self):
        self._led.on()
        await asyncio.sleep_ms(50)
        return self

    async def __aexit__(self, exc_type, exc, tb):
        self._led.off()

async def main():
    led = LED("LED_WHITE")

    async with Spotlight(led):
        # work that benefits from steady illumination
        await asyncio.sleep_ms(200)

asyncio.run(main())

Kad se uđe u blok, __aenter__ se izvršava: LED-ica se uključuje, await za 50 ms smirivanja predaje kontrolu petlji kako bi druge korutine u međuvremenu mogle napredovati, a tijelo bloka započinje čim čekanje završi. Kad blok završi – pri normalnom izlasku, pri iznimci ili pri otkazivanju – __aexit__ se izvršava i LED-ica se ponovno isključuje. Čišćenje se izvršava u svakom slučaju; to je jamstvo koje async with pruža.

The frame capture page shows how to make csi.CSI.snapshot() await-friendly; once that wrapper is in hand, the body of an async with Spotlight(led): block would typically be a capture loop running under the steady illumination.