8.10. Kelas awaitable

8.10.1. Apa itu awaitable

Ketika sebuah coroutine menulis await x, bahasa bertanya kepada x bagaimana cara menunggunya. Objek apa pun yang tahu cara menjawab adalah awaitable. Ada dua jenisnya:

  • Objek coroutine yang dikembalikan oleh fungsi async def. Memanggil send_request() menghasilkan salah satunya setiap kali -- objek coroutine, bukan hasil fungsi. Menulis await send_request() adalah yang benar-benar menjalankan isi fungsi.

  • Objek dari kelas yang mendefinisikan metode __await__. async def adalah singkatan untuk jenis pertama; __await__ adalah cara manual untuk membuat jenis kedua.

Kode aplikasi menggunakan jenis pertama secara default. Jenis kedua ada untuk kasus langka di mana objek itu sendiri perlu menjadi sesuatu yang di-await oleh pemanggil, bukan hasil dari memanggil metode pada objek tersebut.

8.10.2. Dua bentuk secara berdampingan

Logika yang sama ditulis sebagai coroutine dan sebagai kelas 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

Keduanya dapat di-await dengan cara yang sama:

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

Bentuk async def lebih pendek, terbaca seperti Python biasa, dan membiarkan bahasa mengelola semua pembukuan suspend-dan-resume. Bentuk kelas tidak mendapat tambahan apa pun dalam contoh ini.

8.10.3. Kapan bentuk kelas diperlukan

Ketika objek harus menjadi sesuatu yang diserahkan oleh aplikasi -- bukan fungsi yang dipanggil pemanggil untuk mendapatkan coroutine -- bentuk kelas adalah satu-satunya pilihan:

  • Nilai future-like yang dibuat aplikasi, diserahkan ke produsen, dan di-await nanti untuk mengambil hasil yang diproduksi.

  • Primitif kustom yang dibangun di atas primitif yang ada di mana API alaminya adalah await my_thing bukan await my_thing.wait(). Kelas asyncio.Task itu sendiri adalah contoh bawaan -- menulis await task berfungsi karena Task mendefinisikan __await__.

Untuk apa pun yang sesuai dengan bentuk panggil fungsi, dapatkan coroutine, await-nya, async def menang.

8.10.4. Detail protokol

__await__ adalah metode biasa (bukan async def) yang mengembalikan sebuah iterator. Menulisnya sebagai generator -- termasuk setidaknya satu yield dalam isi -- membuatnya menjadi iterator secara otomatis. Setiap yield menangguhkan coroutine yang me-await objek dan menyerahkan kontrol kembali ke event loop; generator dilanjutkan saat berikutnya loop menjadwalkan task. return kosong (atau akhir fungsi) mengakhiri penantian; apa pun yang dihasilkan return menjadi nilai dari ekspresi await.

Dalam praktiknya, kelas langka yang melakukan ini menyerahkan yielding ke awaitable yang ada daripada menggerakkan loop sendiri:

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

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

yield from menggunakan kembali __await__ event yang mendasarinya untuk penangguhan yang sebenarnya. Sebagian besar aplikasi asyncio tidak pernah perlu menulis salah satu bentuk tersebut.