8.12. Gestionari de context asincroni¶
Prezentarea generală Python a introdus gestionarii de context – obiectele pe care le conduc blocurile with, cu __enter__ rulând la intrare și __exit__ rulând la ieșire indiferent de cum se încheie blocul. Gestionarii de context asincroni reprezintă aceeași idee mutată în asyncio: __aenter__ și __aexit__ sunt corutine, astfel încât configurarea sau curățarea poate await ceva. Blocul care îi conduce este async with.
Am folosit deja unul. asyncio.Lock este un gestionar de context asincron; pagina zăvoare l-a folosit ca async with bus_lock: .... Această pagină este despre scrierea unuia pentru resursa proprie a unei aplicații.
8.12.1. Când să scrii unul¶
Când aplicația are o resursă care necesită configurare și dezasamblare împerecheate, iar cel puțin una dintre aceste laturi trebuie să await ceva. Conexiuni de rețea, senzori care necesită o întârziere de stabilizare după configurare, orice blochează ceva la intrare și deblochează la ieșire. Forma with sincronă simplă nu se aplică, deoarece __enter__ și __exit__ ale ei nu pot fi corutine.
8.12.2. Cele două metode¶
async def __aenter__(self)rulează când blocul este intrat. Ceea ce returnează este ceea ce leagă clauza opționalăas namea luiasync with. Returnarea luiselfeste forma cea mai frecventă, dar orice valoare funcționează.async def __aexit__(self, exc_type, exc, tb)rulează când blocul este părăsit.exc_typeesteNonela o ieșire normală; la o excepție (sau o anulare) este clasa excepției, iarexceste instanța. Returnarea unei valori adevărate îi spune lui Python că excepția a fost tratată și nu ar trebui să se propage. Returnarea luiNone(cazul obișnuit) lasă excepția să continue în sus pe lanțul de apeluri după ce rulează curățarea.
8.12.3. Un exemplu lucrat¶
Un strat de încapsulare de tip spot care aprinde un LED pe durata corpului blocului, cu o scurtă întârziere de stabilizare astfel încât iluminarea să fie stabilă înainte de a avea loc orice captură, și care stinge LED-ul la ieșire:
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())
Când blocul este intrat, __aenter__ rulează: LED-ul se aprinde, await-ul de stabilizare de 50 ms cedează controlul buclei astfel încât alte corutine să poată progresa între timp, iar corpul blocului începe odată ce așteptarea se încheie. Când blocul se termină – la o ieșire normală, la o excepție sau la o anulare – __aexit__ rulează și LED-ul se stinge la loc. Curățarea rulează în toate cazurile; aceasta este garanția pe care o oferă async with.
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.