8.10. Clase care pot fi așteptate (awaitable)¶
8.10.1. Ce este un obiect care poate fi așteptat (awaitable)¶
Atunci când o corutină scrie await x, limbajul îi cere lui x să spună cum trebuie așteptat. Orice obiect care știe să răspundă este awaitable. Există două tipuri:
Obiectele corutină pe care le returnează funcțiile
async def. Apelareasend_request()produce de fiecare dată unul dintre acestea – obiectul corutină, nu rezultatul funcției. Scriereaawait send_request()este ceea ce execută efectiv corpul.Obiectele unei clase care definește o metodă
__await__.async defeste forma prescurtată pentru primul tip;__await__este modul manual de a crea cel de-al doilea tip.
Codul aplicației folosește implicit primul tip. Cel de-al doilea tip există pentru cazul rar în care obiectul însuși trebuie să fie lucrul pe care apelantul îl așteaptă cu await, nu rezultatul apelării unei metode asupra lui.
8.10.2. Cele două forme alăturate¶
Aceeași logică scrisă ca o corutină și ca o clasă awaitable:
import asyncio
# async def -- almost always the right choice
async def yield_then_return(value):
await asyncio.sleep_ms(0)
return value
# awaitable class -- equivalent, rarely written
class YieldThenReturn:
def __init__(self, value):
self._value = value
def __await__(self):
yield # let the loop run once
return self._value # value of the ``await`` expression
Ambele pot fi așteptate cu await în același mod:
async def main():
a = await yield_then_return(1)
b = await YieldThenReturn(2)
print(a, b) # prints: 1 2
Forma async def este mai scurtă, se citește ca Python obișnuit și lasă limbajul să gestioneze toată contabilitatea de suspendare și reluare. Forma de clasă nu obține nimic în plus în acest exemplu.
8.10.3. Când forma de clasă își merită locul¶
Atunci când obiectul trebuie să fie ceva ce aplicația vehiculează – nu o funcție pe care apelantul o invocă pentru a obține o corutină – forma de clasă este singura opțiune:
O valoare de tip future pe care aplicația o creează, o predă unui producător și o așteaptă cu
awaitmai târziu pentru a prelua rezultatul produs.O primitivă personalizată construită deasupra uneia existente, unde API-ul natural este
await my_thingmai degrabă decâtawait my_thing.wait(). Clasaasyncio.Taskînsăși este un exemplu încorporat – scriereaawait taskfuncționează deoareceTaskdefinește__await__.
Pentru orice se potrivește formei apelezi o funcție, obții o corutină, o aștepți, async def câștigă.
8.10.4. Detaliile protocolului¶
__await__ este o metodă obișnuită (nu async def) care returnează un iterator. Scrierea ei ca generator – incluzând cel puțin un yield în corp – o transformă automat în unul. Fiecare yield suspendă corutina care așteaptă obiectul cu await și predă controlul înapoi buclei de evenimente; generatorul se reia data următoare când bucla programează sarcina. Un simplu return (sau ajungerea la sfârșit) încheie așteptarea; ceea ce produce return devine valoarea expresiei await.
În practică, rara clasă care face acest lucru predă cedarea (yield) către un obiect awaitable existent, în loc să conducă ea însăși bucla:
class WaitForEvent:
def __init__(self, event):
self._event = event
def __await__(self):
yield from self._event.wait().__await__()
return self._event
yield from reutilizează metoda __await__ a evenimentului subiacent pentru suspendarea efectivă. Majoritatea aplicațiilor asyncio nu au nevoie niciodată să scrie vreuna dintre forme.