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.
Pagina captura de cadre arată cum se face csi.CSI.snapshot() compatibilă cu await; odată ce acel strat de încapsulare este la îndemână, corpul unui bloc async with Spotlight(led): ar fi de obicei o buclă de captură care rulează sub iluminarea constantă.