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
with open("note.txt", "w") as f:
f.write("ciao")
# qui f è già chiuso, anche se write() ha sollevato un'eccezioneDü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
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__.
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,assonrasında elde ettiğiniz değerdir. __exit__(self, exc_type, exc_value, tb)çıkışta çağrılır (her zaman).Truedeğ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:
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
from contextlib import suppress
with suppress(FileNotFoundError):
open("forse-non-esiste.txt").read()
# se il file non c'è, nessun errore propagaTuzak: with yalnızca onu destekleyen nesneler için
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:
from contextlib import contextmanager
@contextmanager
def manage_resource():
# __enter__ code
yield resource
# __exit__ codeKendin dene
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.
İpucu göster
bastır(ValueError) yalnızca ValueError'ı yutar.
3 denemeden sonra çözüm mevcut
Alıştırmayı gözden geçirin
@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.
İpucu göster
with bloğunun içindeki listeyi ortaya çıkarmak için verim öğeleri.
3 denemeden sonra çözüm mevcut
Ek zorluk
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():`.
İ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