Kontextmanager und with: Ressourcen sicher öffnen und schließen
Kurz: Die with-Anweisung stellt sicher, dass Ressourcen wie Dateien, Verbindungen oder Sperren auch bei Fehlern wieder freigegeben werden; eigene Kontextmanager baut man mit Klassen oder contextlib.
Genauer: Wer eine Datei öffnet, muss sie schließen, sonst bleiben Handles offen, Daten ungeschrieben, Sperren gehalten. try/finally funktioniert, ist aber umständlich. with erledigt das automatisch.
Im Detail
Das Muster
with open("daten.txt", encoding="utf-8") as f:
inhalt = f.read()
# hier ist die Datei garantiert geschlossen, auch bei AusnahmeÄquivalent zu try: ... finally: f.close(). Mehrere Ressourcen: with open(a) as x, open(b, "w") as y:. Typische Kontextmanager: Dateien, threading.Lock(), Datenbankverbindungen/Transaktionen (with conn:), tempfile.TemporaryDirectory(), socket, zipfile, unittest.mock.patch, subprocess, HTTP-Sitzungen (requests.Session).
Eigene Kontextmanager
Klasse mit __enter__ und __exit__:
import time
class Stoppuhr:
def __enter__(self):
self.start = time.perf_counter(); return self
def __exit__(self, typ, wert, tb):
print(f"{time.perf_counter() - self.start:.3f}s")
return False # Ausnahme nicht verschluckenGenerator mit contextlib:
from contextlib import contextmanager
@contextmanager
def arbeitsordner(pfad):
alt = os.getcwd(); os.chdir(pfad)
try:
yield
finally:
os.chdir(alt)__exit__ bekommt die Ausnahmeinformation; True zurückgeben unterdrückt sie (selten sinnvoll; contextlib.suppress(FileNotFoundError) ist die sichere Variante).
Weitere Werkzeuge
contextlib.closing,ExitStack(dynamisch viele Ressourcen),redirect_stdout.- async:
async withfür asynchrone Ressourcen (Datenbankpool, HTTP-Clientaiohttp),__aenter__/__aexit__. - Dateien:
Path.read_text()kapseltwithfür Einzeiler. - Transaktionen:
with db.transaction():Commit/Rollback automatisch. - Tests:
with pytest.raises(ValueError):,with patch(...). - Lock:
with lock:verhindert vergessenesrelease()(siehe Mutex/Deadlock).
Typische Fehler und Tipps
- Datei ohne
withoffen lassen (Windows kann sie dann nicht löschen). - Rückgabe aus dem with-Block ist ok:
__exit__läuft trotzdem. - Generator-Kontextmanager ohne
try/finallyräumt bei Ausnahme nicht auf. - Ausnahmen nicht schlucken:
__exit__gibtFalse/Nonezurück. - Immer
encodingbeim Textöffnen angeben. - Ressourcenlecks erkennt man mit
ResourceWarning/-X dev. - Verwandt: RAII (C++),
try-with-resources(Java),defer(Go),using(C#).
Siehe auch: Dateien in Python, Mutex, Dekoratoren