Pelajaran modul (3/4)
Manajer konteks: dengan dan __enter__/__exit__
Pengelola konteks adalah objek yang Anda gunakan dengan with. Ini menjamin hal itu
operasi pengaturan/pembersihan tertentu selalu terjadi, bahkan ketika terjadi kesalahan.
Contoh kanonik: membuka dan menutup file.
Pola with
with open("note.txt", "w") as f:
f.write("ciao")
# qui f è già chiuso, anche se write() ha sollevato un'eccezioneDalam bahasa Inggris sederhana: "dengan sumber daya X terbuka sebagai f, lakukan ini. Setelah selesai
(apa pun yang terjadi), tutup X." Tanpa with Anda harus menulis
a try/finally setiap saat.
Lebih dari satu pada satu waktu
with open("a.txt") as f, open("b.txt") as g:
dati_a = f.read()
dati_b = g.read()Menulis manajer konteks Anda sendiri (kelas)
Anda perlu mendefinisikan dua metode dunder: __enter__ dan __exit__.
class Timer:
def __enter__(self):
import time
self.t0 = time.perf_counter()
return self # è l'oggetto che finisce dopo "as"
def __exit__(self, exc_type, exc_value, traceback):
import time
self.elapsed = time.perf_counter() - self.t0
# ritornare True ingoia l'eccezione; di solito non lo vuoi
return False
with Timer() as t:
sum(range(10**6))
t.elapsed # quanto è durato__enter__(self)dipanggil saat memasuki blok; nilai yang dikembalikan adalah apa yang Anda dapatkan setelahas.__exit__(self, exc_type, exc_value, tb)dipanggil saat keluar (selalu). Jika mengembalikanTrue, pengecualian apa pun ditekan.
Pintasannya: @contextmanager
contextlib.contextmanager memungkinkan Anda menulis pengelola konteks sebagai a
fungsi generator:
from contextlib import contextmanager
@contextmanager
def timer():
import time
t0 = time.perf_counter()
try:
yield # qui sta il blocco "with"
finally:
elapsed = time.perf_counter() - t0
print(f"durata: {elapsed:.4f}s")
with timer():
sum(range(10**6))Kode sebelum yield adalah __enter__, kode setelah adalah __exit__.
try/finally menjamin pembersihan bahkan ketika terjadi kesalahan.
menekan: mengabaikan pengecualian
from contextlib import suppress
with suppress(FileNotFoundError):
open("forse-non-esiste.txt").read()
# se il file non c'è, nessun errore propagaKesalahan: with hanya untuk objek yang mendukungnya
x = 42
with x: # AttributeError: __enter__
...Menulis pengelola konteks dengan @contextmanager
Modul contextlib perpustakaan standar mengekspor dekorator yang sangat nyaman disebut @contextmanager untuk membuat pengelola konteks menggunakan fungsi generator, alih-alih menulis kelas verbose yang menerapkan metode __enter__ dan __exit__. Anda cukup menulis fungsi generator yang menggunakan satu yield:
from contextlib import contextmanager
@contextmanager
def manage_resource():
# __enter__ code
yield resource
# __exit__ codeCobalah sendiri
Gunakan kontekslib.suppress untuk mencoba int('non-numero') mengabaikan ValueError. Setelah blok tetapkan `ok = True`. Evaluasi `oke`.
Tunjukkan petunjuk
supres(ValueError) hanya menelan ValueError.
Solusi tersedia setelah 3 upaya
Tinjau latihan
Tulis manajer konteks `kumpulkan` dengan @contextmanager yang menghasilkan daftar kosong dan, saat keluar, ubah menjadi tuple (cetak). Gunakan untuk menambahkan 1, 2, 3 ke daftar di dalam blok. Pada akhirnya, evaluasi `len(koleksi)` di mana `koleksi` adalah daftar yang dihasilkan.
Tunjukkan petunjuk
hasilkan item untuk mengekspos daftar di dalam blok with.
Solusi tersedia setelah 3 upaya
Tantangan tambahan
Write a custom context manager using the `@contextmanager` decorator from `contextlib`. The context manager must be named `mock_session`. Upon entry, it must append `'start'` to a global list `log_list = []`, yield control using `yield`, and upon exit append `'stop'`. Finally, evaluate `log_list` after using the context manager with `with mock_session():`.
Tunjukkan petunjuk
Gunakan hasil di dalam mock_session untuk menunda eksekusi sebelum menambahkan 'berhenti'.
Solusi tersedia setelah 3 upaya