Ana içeriğe geç
Modül 9 · Ders 3 ders 4Kurstaki 35/36~12 min
Modül dersleri (3/4)

Bağlam yöneticisi: with ve __enter__/__exit__

bağlam yöneticisi, with ile kullandığınız bir nesnedir. Bunu garanti eder hatalar meydana gelse bile belirli kurulum/temizleme işlemleri her zaman gerçekleşir. Kanonik örnek: bir dosyayı açmak ve kapatmak.

with modeli

Python
with open("note.txt", "w") as f:
    f.write("ciao")
# qui f è già chiuso, anche se write() ha sollevato un'eccezione

Düz İngilizce: "kaynak X ile f olarak açıkken bunu yapın. Bittiğinde (ne olursa olsun), X'i kapatın." with olmasaydı yazmanız gerekirdi her seferinde try/finally.

Aynı anda birden fazla

Python
with open("a.txt") as f, open("b.txt") as g:
    dati_a = f.read()
    dati_b = g.read()

Kendi içerik yöneticinizi (sınıf) yazma

İki dunder yöntemi tanımlamanız gerekir: __enter__ ve __exit__.

Python
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
  • Bloğa girildiğinde __enter__(self) çağrılır; döndürülen değer, as sonrasında elde ettiğiniz değerdir.
  • __exit__(self, exc_type, exc_value, tb) çıkışta çağrılır (her zaman). True değerini döndürürse tüm istisnalar bastırılır.

Kısayol: @contextmanager

contextlib.contextmanager bir içerik yöneticisini jeneratör işlevi:

Python
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))

önceki yield kodu __enter__, sonra kodu __exit__'dir. try/finally, hatalar meydana geldiğinde bile temizliği garanti eder.

bastır: bir istisnayı göz ardı et

Python
from contextlib import suppress

with suppress(FileNotFoundError):
    open("forse-non-esiste.txt").read()
# se il file non c'è, nessun errore propaga

Tuzak: with yalnızca onu destekleyen nesneler için

Python
x = 42
with x:  # AttributeError: __enter__
    ...

@contextmanager ile içerik yöneticileri yazma

Standart kütüphanenin contextlib modülü, __enter__ ve __exit__ yöntemlerini uygulayan ayrıntılı sınıflar yazmak yerine, oluşturucu işlevleri kullanarak bağlam yöneticileri oluşturmak için @contextmanager adlı son derece kullanışlı bir dekoratörü dışa aktarır. Tek bir yield kullanan bir oluşturucu işlevi yazmanız yeterlidir:

Python
from contextlib import contextmanager

@contextmanager
def manage_resource():
    # __enter__ code
    yield resource
    # __exit__ code

Kendin dene

Egzersiz#python.m9.l3.e1
Denemeler: 0Yükleniyor…

ValueError'ı yok sayarak int('non-numero') işlevini denemek için contextlib.suppress'i kullanın. Bloktan sonra `ok = True` komutunu atayın. 'Tamam'ı değerlendirin.

Düzenleyici yükleniyor…
İpucu göster

bastır(ValueError) yalnızca ValueError'ı yutar.

3 denemeden sonra çözüm mevcut

Alıştırmayı gözden geçirin

Egzersiz#python.m9.l3.e2
Denemeler: 0Yükleniyor…

@contextmanager ile boş bir liste veren ve çıkışta bunu bir demet'e dönüştüren (yazdıran) bir bağlam yöneticisi 'collect' yazın. Bloğun içindeki listeye 1, 2, 3'ü eklemek için bunu kullanın. Sonunda, 'len(collection)' değerini değerlendirin; burada 'collection' elde edilen listedir.

Düzenleyici yükleniyor…
İpucu göster

with bloğunun içindeki listeyi ortaya çıkarmak için verim öğeleri.

3 denemeden sonra çözüm mevcut

Ek zorluk

Egzersiz#python.m9.l3.e3
Denemeler: 0Yükleniyor…

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():`.

Düzenleyici yükleniyor…
İpucu göster

'Durdur' eklemeden önce yürütmeyi askıya almak için Mock_session içindeki verimi kullanın.

3 denemeden sonra çözüm mevcut