8.10. Await edilebilir sınıflar

8.10.1. Await edilebilir nedir

Bir eşyordam await x yazdığında, dil x nesnesine onu nasıl bekleyeceğini sorar. Bu soruya nasıl yanıt vereceğini bilen her nesne await edilebilirdir. İki türü vardır:

  • async def fonksiyonlarının döndürdüğü eşyordam nesneleri. send_request() çağrısı her seferinde bunlardan birini – fonksiyonun sonucunu değil, eşyordam nesnesini – üretir. await send_request() yazmak gövdeyi gerçekten çalıştıran şeydir.

  • Bir __await__ metodu tanımlayan bir sınıfın nesneleri. async def ilk türün kısayoludur; __await__ ise ikinci türü oluşturmanın elle yapılan yoludur.

Uygulama kodu varsayılan olarak ilk türü kullanır. İkinci tür, çağıranın bir metodu çağırmasının sonucunu değil, nesnenin kendisinin await edilecek şey olması gerektiği nadir durumlar için vardır.

8.10.2. İki biçim yan yana

Aynı mantığın hem bir eşyordam hem de bir await edilebilir sınıf olarak yazılışı:

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

Her ikisi de aynı şekilde await edilebilir:

async def main():
    a = await yield_then_return(1)
    b = await YieldThenReturn(2)
    print(a, b)                     # prints: 1 2

async def biçimi daha kısadır, normal Python gibi okunur ve tüm askıya alma ve devam ettirme defter tutmasını dilin yönetmesini sağlar. Bu örnekte sınıf biçimi fazladan hiçbir şey kazandırmaz.

8.10.3. Sınıf biçiminin yerini hak ettiği durum

Nesnenin, çağıranın bir eşyordam elde etmek için çağırdığı bir fonksiyon değil de, uygulamanın etrafta dolaştırdığı bir şey olması gerektiğinde, tek seçenek sınıf biçimidir:

  • Uygulamanın oluşturduğu, bir üreticiye verdiği ve üretilen sonucu almak için daha sonra await ettiği future benzeri bir değer.

  • Doğal API’nin await my_thing.wait() yerine await my_thing olduğu, mevcut bir ilkel üzerine inşa edilmiş özel bir ilkel. asyncio.Task sınıfının kendisi yerleşik bir örnektir – await task yazmak çalışır çünkü Task bir __await__ tanımlar.

Bir fonksiyon çağır, bir eşyordam al, onu await et biçimine uyan her şey için async def kazanır.

8.10.4. Protokol ayrıntıları

__await__, bir yineleyici döndüren sıradan bir metottur (async def değil). Onu bir üreteç olarak yazmak – gövdede en az bir yield bulundurmak – onu otomatik olarak bir üretece dönüştürür. Her yield, nesneyi await eden eşyordamı askıya alır ve kontrolü olay döngüsüne geri verir; döngü görevi bir sonraki kez zamanladığında üreteç devam eder. Çıplak bir return (ya da sona ulaşmak) beklemeyi bitirir; return‘ün ürettiği her ne ise await ifadesinin değeri olur.

Uygulamada bunu yapan nadir sınıf, döngüyü kendisi sürmek yerine yield etmeyi mevcut bir await edilebilire devreder:

class WaitForEvent:
    def __init__(self, event):
        self._event = event

    def __await__(self):
        yield from self._event.wait().__await__()
        return self._event

yield from, gerçek askıya alma işlemi için alttaki olayın __await__ metodunu yeniden kullanır. Çoğu asyncio uygulamasının bu biçimlerden herhangi birini yazmaya hiç ihtiyacı olmaz.