8.10. Awaitable třídy¶
8.10.1. Co je awaitable¶
Když korutina zapíše await x, jazyk se x zeptá, jak na něj čekat. Jakýkoli objekt, který umí odpovědět, je awaitable. Existují dva druhy:
Objekty korutin, které vracejí funkce
async def. Volánísend_request()pokaždé vytvoří jeden z nich – objekt korutiny, nikoli výsledek funkce. Teprve zápisawait send_request()skutečně spustí tělo.Objekty třídy, která definuje metodu
__await__.async defje zkratkou pro první druh;__await__je ručním způsobem, jak vytvořit druhý druh.
Aplikační kód používá ve výchozím nastavení první druh. Druhý druh existuje pro vzácný případ, kdy objekt samotný potřebuje být tím, na co volající awaituje, nikoli výsledkem volání metody na něm.
8.10.2. Obě formy vedle sebe¶
Stejná logika zapsaná jako korutina a jako awaitable třída:
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
Na obojí lze awaitovat stejným způsobem:
async def main():
a = await yield_then_return(1)
b = await YieldThenReturn(2)
print(a, b) # prints: 1 2
Forma async def je kratší, čte se jako běžný Python a nechává jazyk spravovat veškerou administrativu kolem pozastavování a obnovování. Forma třídy v tomto příkladu nezískává nic navíc.
8.10.3. Kdy si forma třídy zaslouží své místo¶
Když objekt musí být něčím, co aplikace předává dál – nikoli funkcí, kterou volající vyvolá, aby získal korutinu – je forma třídy jedinou možností:
Hodnota podobná future, kterou aplikace vytvoří, předá producentovi a později na ni
awaituje, aby získala vyprodukovaný výsledek.Vlastní primitivum postavené nad existujícím, kde je přirozeným API
await my_thingspíše nežawait my_thing.wait(). Vestavěným příkladem je samotná třídaasyncio.Task– zápisawait taskfunguje, protožeTaskdefinuje__await__.
Pro cokoli, co odpovídá tvaru zavolej funkci, získej korutinu, počkej na ni, vítězí async def.
8.10.4. Podrobnosti protokolu¶
__await__ je běžná metoda (nikoli async def), která vrací iterátor. Když ji zapíšeme jako generátor – s alespoň jedním yield v těle – stane se jím automaticky. Každý yield pozastaví korutinu, která na objekt awaituje, a předá řízení zpět smyčce událostí; generátor pokračuje, až smyčka úlohu příště naplánuje. Holé return (nebo dosažení konce) čekání ukončí; cokoli return vyprodukuje, stane se hodnotou výrazu await.
V praxi vzácná třída, která toto dělá, předává yieldování existujícímu awaitable, namísto aby smyčku řídila sama:
class WaitForEvent:
def __init__(self, event):
self._event = event
def __await__(self):
yield from self._event.wait().__await__()
return self._event
yield from znovu využívá __await__ podkladové události pro skutečné pozastavení. Většina asyncio aplikací nikdy nepotřebuje psát ani jednu z forem.