Belajar dengan membaca secara berurutan

contextlib — Manajemen Resource dan with Kustom

Pelajari @contextmanager plus yield untuk membuat with tanpa class, cleanup pasti via try/finally, dan menelan exception spesifik dengan suppress lewat contoh.

contextlib adalah modul yang harus kamu pakai ketika ingin menulis with statement sendiri. Kita akan membahas dua alat paling sederhananya secara berurutan: @contextmanager untuk cara paling sederhana mendefinisikannya, dan suppress untuk menelan exception tertentu.

@contextmanager — definisikan with statement dengan mudah

with statement Python adalah cara aman untuk menangani "hal-hal yang harus kamu bersihkan setelah dipakai"open file, koneksi DB, akuisisi lock, dan sebagainya. Untuk membuat class bekerja dengan with dengan tangan, kamu perlu mendefinisikan __enter__ / __exit__, yang merupakan banyak boilerplate. @contextmanager adalah jalan pintas: tulis satu generator (fungsi yang berisi yield) dan kamu mendapatkan context manager yang bekerja dengan with. Kode sebelum yield adalah "awal aksi", dan kode setelahnya adalah "cleanup".

struktur @contextmanager
@contextmanagerdef section(name):Setup(sebelum yield)yieldTeardown(setelah yield)
Fungsi generator plus @contextmanager — bagian sebelum yield adalah setara __enter__ (setup), dan bagian setelah yield adalah setara __exit__ (teardown). Value yield adalah yang diikat oleh as di with statement.
from contextlib import contextmanager

# --- Referensi: membangun class yang kompatibel dengan with ----------
# class Section:
#     def __init__(self, name):
#         self.name = name
#     def __enter__(self):
#         print(f"--- {self.name} start ---")
#         return self                 # value yang diikat oleh `as` with
#     def __exit__(self, exc_type, exc, tb):
#         print(f"--- {self.name} end ---")
# ----------------------------------------------------------

# Versi @contextmanager: satu fungsi generator melakukan pekerjaan yang sama
@contextmanager
def section(name):
    print(f"--- {name} start ---")
    yield                       # tubuh with jalan di sini
    print(f"--- {name} end ---")

# Pemakaian
with section("agregasi"):
    total = sum(range(100))
    print("Total:", total)

# Output:
# --- agregasi start ---
# Total: 4950
# --- agregasi end ---
Penyederhanaan versi class → versi @contextmanager
Versi class__init__ / __enter__ /__exit__ — 3 methodSederhanakan dengan@contextmanagerVersi generatorsebelum yield = setupsetelah yield = teardown
Mengganti class dengan __init__ / __enter__ / __exit__ (tiga method) dengan satu fungsi generator yang didekorasi oleh @contextmanager memetakan kode sebelum/setelah yield langsung ke setup/teardown — kode jauh lebih sedikit.

Pakai try/finally untuk menjamin cleanup bahkan saat exception

Kode setelah yield mungkin tidak jalan jika exception dilempar di dalam blok with. Untuk cleanup yang harus selalu terjadi — menutup file, melepas lock — bungkus tubuh generator dalam try: yield finally: cleanup() untuk keamanan.

Bangun transaction(name) yang memodelkan transaksi DB dengan @contextmanager. Cetak BEGIN sebelum dan COMMIT setelah, dengan SQL di dalam blok terlihat di antaranya.

① Impor contextmanager dari contextlib

② Definisikan fungsi transaction(name) yang didekorasi dengan @contextmanager — cetak [name] BEGIN, kemudian yield, kemudian cetak [name] COMMIT setelah

③ Di dalam with transaction("order_create"):, cetak dua baris SQL: INSERT INTO orders (id, total) VALUES (1, 1980) dan UPDATE inventory SET stock = stock - 1

(Jika kode kamu jalan dengan benar, penjelasannya akan muncul.)

Python Editor

Jalankan kode untuk melihat output

suppress — telan exception tertentu

contextlib.suppress(ExceptionType, ...) adalah context manager untuk menelan exception yang ditentukan dan melanjutkan eksekusi. Pola "abaikan saja exception ini dan lanjutkan" — setara dengan try: ... except KeyError: pass — pas dalam satu baris. Kamu bisa mendaftarkan beberapa tipe exception sekaligus, dan apa pun di luar daftar merambat secara normal.

from contextlib import suppress
import os

# "Jalankan dengan nilai default bahkan jika file tidak ada"
config = {"theme": "light", "font_size": 14}
with suppress(FileNotFoundError):
    with open("user_config.txt") as f:
        config["theme"] = f.read().strip()
# Tidak akan crash jika user_config.txt tidak ada — config tetap pada default
print(config)
# → {'theme': 'light', 'font_size': 14}

# "Lewati diam-diam jika sudah dihapus"
with suppress(FileNotFoundError):
    os.remove("old.tmp")
print("Hapus selesai (OK jika tidak ada)")

Pakai suppress untuk terus berjalan bahkan ketika mengambil key yang hilang dari dict.

① Impor suppress dari contextlib

② Definisikan dict user = {"name": "Budi", "email": "budi@example.com"} (catatan: tidak ada key age)

③ Di dalam with suppress(KeyError):, coba akses user["age"] — konfirmasi bahwa key yang hilang tidak crash

④ Tepat setelah blok, cetak Lanjut: tidak crash

⑤ Cetak nama dan email pengguna dalam satu baris sebagai Pengguna: ◯ <◯>

Python Editor

Jalankan kode untuk melihat output
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Ketika kamu mendekorasi fungsi generator dengan @contextmanager, mengapa ia perlu yield tepat sekali?

Soal 2Di dalam with suppress(KeyError):, apa yang terjadi ketika KeyError dilempar?