EMZETT.
Login

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 verschlucken

Generator 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 with für asynchrone Ressourcen (Datenbankpool, HTTP-Client aiohttp), __aenter__/__aexit__.
  • Dateien: Path.read_text() kapselt with für Einzeiler.
  • Transaktionen: with db.transaction(): Commit/Rollback automatisch.
  • Tests: with pytest.raises(ValueError):, with patch(...).
  • Lock: with lock: verhindert vergessenes release() (siehe Mutex/Deadlock).

Typische Fehler und Tipps

  • Datei ohne with offen lassen (Windows kann sie dann nicht löschen).
  • Rückgabe aus dem with-Block ist ok: __exit__ läuft trotzdem.
  • Generator-Kontextmanager ohne try/finally räumt bei Ausnahme nicht auf.
  • Ausnahmen nicht schlucken: __exit__ gibt False/None zurück.
  • Immer encoding beim 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