8.10. Čekljive klase¶
8.10.1. Što je čekljiv objekt¶
Kada korutina napiše await x, jezik pita x kako da ga pričeka. Svaki objekt koji zna odgovoriti je čekljiv. Postoje dvije vrste:
Objekti korutina koje vraćaju funkcije
async def. Pozivanjesend_request()svaki put proizvodi jedan od njih – objekt korutine, a ne rezultat funkcije. Pisanjeawait send_request()je ono što zapravo pokreće tijelo.Objekti klase koja definira metodu
__await__.async defje kratica za prvu vrstu;__await__je ručni način za stvaranje druge vrste.
Kôd aplikacije prema zadanim postavkama koristi prvu vrstu. Druga vrsta postoji za rijedak slučaj kada sam objekt treba biti ono što pozivatelj awaita, a ne rezultat pozivanja metode nad njim.
8.10.2. Dva oblika jedan uz drugi¶
Ista logika napisana kao korutina i kao čekljiva klasa:
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
Oba se mogu awaitati na isti način:
async def main():
a = await yield_then_return(1)
b = await YieldThenReturn(2)
print(a, b) # prints: 1 2
Oblik async def je kraći, čita se poput uobičajenog Pythona i prepušta jeziku da upravlja cijelim knjigovodstvom obustave i nastavka. Oblik s klasom u ovom primjeru ne dobiva ništa dodatno.
8.10.3. Kada oblik s klasom zaslužuje svoje mjesto¶
Kada objekt mora biti nešto što aplikacija proslijeđuje – a ne funkcija koju pozivatelj poziva da bi dobio korutinu – oblik s klasom je jedina opcija:
Vrijednost nalik futuru koju aplikacija stvara, predaje proizvođaču i kasnije
awaita kako bi dohvatila proizvedeni rezultat.Prilagođeni primitiv izgrađen na postojećem gdje je prirodni API
await my_thingumjestoawait my_thing.wait(). Sama klasaasyncio.Taskugrađeni je primjer – pisanjeawait taskfunkcionira jerTaskdefinira__await__.
Za sve što odgovara obliku pozovi funkciju, dobij korutinu, počekaj je, async def pobjeđuje.
8.10.4. Pojedinosti protokola¶
__await__ je obična metoda (ne async def) koja vraća iterator. Pisanje u obliku generatora – uključujući barem jedan yield u tijelu – automatski ga čini takvim. Svaki yield obustavlja korutinu koja awaita objekt i predaje kontrolu natrag petlji događaja; generator se nastavlja sljedeći put kad petlja rasporedi zadatak. Goli return (ili kraj tijela) završava čekanje; što god return proizvede postaje vrijednost izraza await.
U praksi rijetka klasa koja to čini prepušta prepuštanje kontrole postojećem čekljivom objektu umjesto da sama pogoni petlju:
class WaitForEvent:
def __init__(self, event):
self._event = event
def __await__(self):
yield from self._event.wait().__await__()
return self._event
yield from ponovno koristi __await__ osnovnog događaja za stvarno obustavljanje. Većini asyncio aplikacija nikada ne treba pisati nijedan od ova dva oblika.