2.24. Správci kontextu¶
Příkaz with spustí inicializační kód, pak tělo a nakonec úklidový kód – se zárukou, že úklid proběhne i tehdy, když tělo někde uprostřed selže. Dvojici metod, která dodává inicializaci a úklid, se říká správce kontextu.
Tvar je:
with <expression> as <name>:
<body>
Výraz vrací správce kontextu. Python zavolá jeho metodu __enter__, volitelně naváže výsledek na <name>, spustí tělo a poté zavolá __exit__ – ať už tělo proběhlo normálně, nebo vyvolalo výjimku.
__exit__ se spustí na konci bloku, ať se uvnitř něj stane cokoli.¶
2.24.1. Použití správce kontextu¶
Kanonickým příkladem je otevření souboru:
with open("data.txt") as f:
text = f.read()
# f is now closed, even if read() failed
open() vrací souborový objekt, který je sám správcem kontextu; __enter__ vrátí soubor a __exit__ jej zavře. Blok with činí z „po dokončení vždy zavřít soubor“ výchozí chování místo něčeho, co si volající musí pamatovat.
2.24.1.1. Více správců kontextu¶
Jediný příkaz with může najednou vstoupit do několika správců kontextu oddělených čárkami:
with open("input.txt") as src, open("output.txt", "w") as dst:
dst.write(src.read())
Ekvivalentní dvěma vnořeným blokům with, ale plošší. Správci se zadávají zleva doprava a opouštějí se v opačném pořadí; pokud __enter__ u pravého správce vyvolá výjimku, __exit__ levého správce se přesto spustí.
2.24.2. Napsání správce kontextu¶
Jako správce kontextu funguje jakákoli třída s metodami __enter__ a __exit__:
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")
Výstup:
--- setup ---
doing the work
--- end setup ---
__exit__ přijímá tři argumenty popisující výjimku, která ukončila blok, nebo tři hodnoty None, pokud blok proběhl normálně. Vrácení False (nebo None) nechá jakoukoli výjimku po úklidu propagovat dál; vrácení True by ji pohltilo.
Správce kontextu používejte pro jakýkoli prostředek, který má životní cyklus „otevřít / zavřít“ nebo „získat / uvolnit“ – nejen pro soubory. Tento vzor udržuje úklid spárovaný s inicializací v místě, kde se obojí zavádí, takže zapomenuté zavření uprostřed dlouhé funkce nemůže prostředek nechat uniknout.