8.10. Odotettavat (awaitable) luokat¶
8.10.1. Mikä odotettava on¶
Kun korutiini kirjoittaa await x, kieli kysyy x:ltä, miten sitä odotetaan. Mikä tahansa objekti, joka osaa vastata, on odotettava (awaitable). Niitä on kahdenlaisia:
Korutiiniobjektit, jotka
async def-funktiot palauttavat.send_request()-kutsu tuottaa yhden näistä joka kerta – korutiiniobjektin, ei funktion tulosta.await send_request()-kirjoittaminen on se, mikä todella suorittaa rungon.Sellaisen luokan objektit, joka määrittelee
__await__-metodin.async defon lyhenne ensimmäiselle tyypille;__await__on manuaalinen tapa luoda jälkimmäinen tyyppi.
Sovelluskoodi käyttää oletuksena ensimmäistä tyyppiä. Toinen tyyppi on olemassa harvinaista tapausta varten, jossa objektin itsensä on oltava se, jota kutsuja awaittaa, eikä sen metodin kutsumisen tulos.
8.10.2. Kaksi muotoa rinnakkain¶
Sama logiikka kirjoitettuna korutiinina ja odotettavana luokkana:
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
Molempia voidaan awaittaa samalla tavalla:
async def main():
a = await yield_then_return(1)
b = await YieldThenReturn(2)
print(a, b) # prints: 1 2
async def -muoto on lyhyempi, lukeutuu kuin tavallinen Python ja antaa kielen hoitaa kaiken keskeytys- ja jatkamiskirjanpidon. Luokkamuoto ei saa tässä esimerkissä mitään lisäarvoa.
8.10.3. Milloin luokkamuoto ansaitsee paikkansa¶
Kun objektin on oltava jotain, jota sovellus välittää eteenpäin – eikä funktio, jota kutsuja kutsuu saadakseen korutiinin – luokkamuoto on ainoa vaihtoehto:
Future-tyyppinen arvo, jonka sovellus luo, antaa tuottajalle ja
awaittaa myöhemmin noutaakseen tuotetun tuloksen.Mukautettu primitiivi, joka on rakennettu olemassa olevan päälle ja jossa luonteva API on
await my_thingeikäawait my_thing.wait().asyncio.Task-luokka itse on sisäänrakennettu esimerkki –await task-kirjoittaminen toimii, koskaTaskmäärittelee__await__.
Kaikelle, mikä sopii muotoon kutsu funktiota, saa korutiinin, odota sitä, async def voittaa.
8.10.4. Protokollan yksityiskohdat¶
__await__ on tavallinen metodi (ei async def), joka palauttaa iteraattorin. Sen kirjoittaminen generaattoriksi – sisällyttämällä runkoon vähintään yksi yield – tekee siitä sellaisen automaattisesti. Jokainen yield keskeyttää korutiinin, joka awaittaa objektia, ja luovuttaa hallinnan takaisin tapahtumasilmukalle; generaattori jatkuu seuraavan kerran, kun silmukka ajastaa tehtävän. Pelkkä return (tai lopun ohi putoaminen) päättää odotuksen; mitä ikinä return tuottaa, siitä tulee await -lausekkeen arvo.
Käytännössä se harvinainen luokka, joka tekee tämän, luovuttaa yield-toiminnan olemassa olevalle odotettavalle sen sijaan, että ohjaisi silmukkaa itse:
class WaitForEvent:
def __init__(self, event):
self._event = event
def __await__(self):
yield from self._event.wait().__await__()
return self._event
yield from käyttää uudelleen taustalla olevan tapahtuman __await__ -metodia varsinaiseen keskeyttämiseen. Useimpien asyncio-sovellusten ei koskaan tarvitse kirjoittaa kumpaakaan muotoa.