8.12. Async context manager

Ikhtisar Python memperkenalkan context manager -- objek yang dikendalikan oleh blok with, dengan __enter__ berjalan saat masuk dan __exit__ berjalan saat keluar tidak peduli bagaimana blok berakhir. Async context manager adalah ide yang sama yang dipindahkan ke asyncio: __aenter__ dan __aexit__ adalah coroutine, sehingga setup atau pembersihan dapat melakukan await. Blok yang mengendalikannya adalah async with.

Kita sudah menggunakannya. asyncio.Lock adalah async context manager; halaman lock menggunakannya sebagai async with bus_lock: .... Halaman ini membahas cara menulis satu untuk sumber daya aplikasi sendiri.

8.12.1. Kapan menulis satu

Ketika aplikasi memiliki sumber daya yang membutuhkan setup dan pembongkaran yang berpasangan, dan setidaknya satu dari sisi tersebut harus melakukan await. Koneksi jaringan, sensor yang membutuhkan penundaan stabilisasi setelah konfigurasi, apa pun yang mengunci sesuatu saat masuk dan membukanya saat keluar. Bentuk with sinkron biasa tidak berlaku karena __enter__ dan __exit__-nya tidak bisa berupa coroutine.

8.12.2. Dua metode

  • async def __aenter__(self) berjalan saat blok dimasuki. Apa pun yang dikembalikannya adalah yang diikat oleh klausa opsional as name dari async with. Mengembalikan self adalah bentuk paling umum, tetapi nilai apa pun bisa.

  • async def __aexit__(self, exc_type, exc, tb) berjalan saat blok keluar. exc_type adalah None pada keluar normal; pada pengecualian (atau pembatalan) itu adalah kelas pengecualian, dan exc adalah instance-nya. Mengembalikan nilai truthy memberi tahu Python bahwa pengecualian telah ditangani dan tidak perlu merambat. Mengembalikan None (kasus biasa) membiarkan pengecualian terus ke atas rantai panggilan setelah pembersihan selesai.

8.12.3. Contoh yang dikerjakan

Pembungkus sorotan yang menyalakan LED untuk isi blok, dengan penundaan stabilisasi singkat agar pencahayaan stabil sebelum pengambilan gambar terjadi, dan mematikan LED kembali saat keluar:

import asyncio
from machine import LED


class Spotlight:
    def __init__(self, led):
        self._led = led

    async def __aenter__(self):
        self._led.on()
        await asyncio.sleep_ms(50)
        return self

    async def __aexit__(self, exc_type, exc, tb):
        self._led.off()

async def main():
    led = LED("LED_WHITE")

    async with Spotlight(led):
        # work that benefits from steady illumination
        await asyncio.sleep_ms(200)

asyncio.run(main())

Saat blok dimasuki, __aenter__ berjalan: LED menyala, penundaan 50 ms await menghasilkan kontrol ke loop sehingga coroutine lain dapat membuat kemajuan sementara itu, dan isi blok dimulai setelah penantian selesai. Saat blok berakhir -- baik keluar normal, pengecualian, maupun pembatalan -- __aexit__ berjalan dan LED mati kembali. Pembersihan berjalan di setiap kasus; itulah jaminan yang diberikan async with.

The frame capture page shows how to make csi.CSI.snapshot() await-friendly; once that wrapper is in hand, the body of an async with Spotlight(led): block would typically be a capture loop running under the steady illumination.