Bağlam yöneticileri ve with: kaynakları güvenle açmak ve kapatmak
Kısaca: with ifadesi, dosyalar, bağlantılar veya kilitler gibi kaynakların hatada bile yeniden serbest bırakılmasını sağlar; kendi bağlam yöneticilerini sınıflarla veya contextlib ile kurarsın.
Biraz daha ayrıntılı: Bir dosyayı açan onu kapatmalıdır, aksi hâlde tutamaçlar açık, veriler yazılmamış, kilitler tutulmuş kalır. try/finally çalışır ama hantaldır. with bunu otomatik yapar.
Ayrıntılı
Kalıp
with open("data.txt", encoding="utf-8") as f:
content = f.read()
# burada dosyanın istisna olsa bile kapalı olduğu garantitry: ... finally: f.close() ile eşdeğerdir. Birkaç kaynak: with open(a) as x, open(b, "w") as y:. Tipik bağlam yöneticileri: dosyalar, threading.Lock(), veri tabanı bağlantıları/işlemleri (with conn:), tempfile.TemporaryDirectory(), socket, zipfile, unittest.mock.patch, subprocess, HTTP oturumları (requests.Session).
Kendi bağlam yöneticilerin
__enter__ ve __exit__ ile sınıf:
import time
class Stopwatch:
def __enter__(self):
self.start = time.perf_counter(); return self
def __exit__(self, typ, value, tb):
print(f"{time.perf_counter() - self.start:.3f}s")
return False # istisnayı yutmacontextlib ile üreteç:
from contextlib import contextmanager
@contextmanager
def workdir(path):
old = os.getcwd(); os.chdir(path)
try:
yield
finally:
os.chdir(old)__exit__ istisna bilgisini alır; True döndürmek onu bastırır (nadiren mantıklı; contextlib.suppress(FileNotFoundError) güvenli varyanttır).
Daha fazla araç
contextlib.closing,ExitStack(dinamik olarak çok kaynak),redirect_stdout.- async: eşzamansız kaynaklar için
async with(veri tabanı havuzu, HTTP istemcisiaiohttp),__aenter__/__aexit__. - Dosyalar:
Path.read_text()tek satırlıklar içinwith’i sarar. - İşlemler:
with db.transaction():commit/rollback’i otomatik yapar. - Testler:
with pytest.raises(ValueError):,with patch(...). - Kilit:
with lock:unutulmuş birrelease()’i önler (bkz. mutex/deadlock).
Tipik hatalar ve ipuçları
- Bir dosyayı
witholmadan açık bırakmak (Windows bunu silemez). - with bloğundan dönmek sorun değildir:
__exit__yine çalışır. try/finallyolmayan bir üreteç bağlam yöneticisi istisnada temizlik yapmaz.- İstisnaları yutma:
__exit__False/Nonedöndürür. - Metin açarken her zaman
encodingver. - Kaynak sızıntıları
ResourceWarning/-X devile tespit edilir. - İlgili: RAII (C++),
try-with-resources(Java),defer(Go),using(C#).
Ayrıca bak: Python’da dosyalar, Mutex