2.24. Gestionari de context¶
Instrucțiunea with rulează cod de configurare, apoi un corp, apoi cod de finalizare – cu garanția că finalizarea se execută chiar și atunci când corpul eșuează la jumătatea execuției. Perechea de metode care furnizează configurarea și finalizarea se numește gestionar de context.
Forma este:
with <expression> as <name>:
<body>
Expresia returnează un gestionar de context. Python apelează metoda sa __enter__, leagă opțional rezultatul de <name>, rulează corpul, apoi apelează __exit__ – indiferent dacă corpul s-a încheiat normal sau a ridicat o excepție.
__exit__ rulează la sfârșitul blocului, indiferent de ce se întâmplă în interiorul acestuia.¶
2.24.1. Utilizarea unui gestionar de context¶
Exemplul canonic este deschiderea unui fișier:
with open("data.txt") as f:
text = f.read()
# f is now closed, even if read() failed
open() returnează un obiect fișier care este el însuși un gestionar de context; __enter__ returnează fișierul, iar __exit__ îl închide. Blocul with face din „închide întotdeauna fișierul la final” comportamentul implicit, în loc de ceva pe care apelantul trebuie să-și amintească.
2.24.1.1. Mai mulți gestionari de context¶
O singură instrucțiune with poate intra în mai mulți gestionari de context deodată, separați prin virgule:
with open("input.txt") as src, open("output.txt", "w") as dst:
dst.write(src.read())
Echivalent cu două blocuri with imbricate, dar mai plat. Gestionarii sunt intrați de la stânga la dreapta și ieșiți în ordine inversă; dacă __enter__ de pe gestionarul din dreapta ridică o excepție, __exit__ al gestionarului din stânga se execută în continuare.
2.24.2. Scrierea unui gestionar de context¶
Orice clasă cu metodele __enter__ și __exit__ funcționează ca un gestionar de context:
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")
Ieșire:
--- setup ---
doing the work
--- end setup ---
__exit__ primește trei argumente care descriu excepția ce a încheiat blocul, sau trei valori None dacă blocul s-a încheiat normal. Returnarea valorii False (sau None) lasă orice excepție să se propage după finalizare; returnarea valorii True ar înghiți-o.
Folosește gestionari de context pentru orice resursă care are un ciclu de viață de tip „deschidere / închidere” sau „achiziție / eliberare” – nu doar pentru fișiere. Tiparul păstrează curățarea împerecheată cu configurarea, în punctul în care ambele sunt introduse, astfel încât o închidere uitată la mijlocul unei funcții lungi nu poate scurge resursa.