2.24. Context managers¶
De with-instructie draait setup-code, daarna een body, daarna teardown-code – met de garantie dat de teardown draait, zelfs wanneer de body halverwege faalt. Het paar methoden dat de setup en teardown levert, wordt een context manager genoemd.
De vorm is:
with <expression> as <name>:
<body>
De expressie geeft een context manager terug. Python roept zijn __enter__-methode aan, bindt optioneel het resultaat aan <name>, draait de body, en roept vervolgens __exit__ aan – of de body nu normaal voltooide of een uitzondering opwierp.
__exit__ draait aan het einde van het blok, wat er ook binnenin gebeurt.¶
2.24.1. Een context manager gebruiken¶
Het canonieke voorbeeld is het openen van een bestand:
with open("data.txt") as f:
text = f.read()
# f is now closed, even if read() failed
open() geeft een bestandsobject terug dat zelf een context manager is; __enter__ geeft het bestand terug, en __exit__ sluit het. Het with-blok maakt van “sluit het bestand altijd af wanneer je klaar bent” de standaard in plaats van iets dat de aanroeper moet onthouden.
2.24.1.1. Meerdere context managers¶
Een enkele with-instructie kan meerdere context managers tegelijk binnengaan, gescheiden door komma’s:
with open("input.txt") as src, open("output.txt", "w") as dst:
dst.write(src.read())
Equivalent aan twee geneste with-blokken, maar platter. De managers worden van links naar rechts binnengegaan en in omgekeerde volgorde verlaten; als __enter__ op de rechtermanager opwerpt, draait de __exit__ van de linkermanager nog steeds.
2.24.2. Een context manager schrijven¶
Elke klasse met __enter__- en __exit__-methoden werkt als een context manager:
class Section:
def __init__(self, label):
self.label = label
def __enter__(self):
print("---", self.label, "---")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("--- end", self.label, "---")
return False
with Section("setup"):
print("doing the work")
Uitvoer:
--- setup ---
doing the work
--- end setup ---
__exit__ ontvangt drie argumenten die de uitzondering beschrijven die het blok beëindigde, of drie None-waarden als het blok normaal voltooide. Het teruggeven van False (of None) laat elke uitzondering na de teardown doorvloeien; het teruggeven van True zou die opslokken.
Gebruik context managers voor elke resource die een levenscyclus van “openen / sluiten” of “verkrijgen / vrijgeven” heeft – niet alleen bestanden. Het patroon houdt opruiming gekoppeld aan setup op het punt waar beide worden geïntroduceerd, zodat een vergeten sluiting midden in een lange functie de resource niet kan lekken.