2.24. Kontexthanterare¶
with-satsen kör uppstartskod, sedan en kropp och därefter nedmonteringskod – med en garanti att nedmonteringen körs även när kroppen misslyckas halvvägs. Paret av metoder som tillhandahåller uppstart och nedmontering kallas en kontexthanterare.
Formen är:
with <expression> as <name>:
<body>
Uttrycket returnerar en kontexthanterare. Python anropar dess __enter__-metod, binder eventuellt resultatet till <name>, kör kroppen och anropar sedan __exit__ – oavsett om kroppen slutfördes normalt eller utlöste ett undantag.
__exit__ körs i slutet av blocket oavsett vad som händer inuti det.¶
2.24.1. Att använda en kontexthanterare¶
Det kanoniska exemplet är att öppna en fil:
with open("data.txt") as f:
text = f.read()
# f is now closed, even if read() failed
open() returnerar ett filobjekt som självt är en kontexthanterare; __enter__ returnerar filen, och __exit__ stänger den. with-blocket gör ”stäng alltid filen när du är klar” till standard snarare än något som anroparen måste komma ihåg.
2.24.1.1. Flera kontexthanterare¶
En enda with-sats kan gå in i flera kontexthanterare samtidigt, åtskilda med kommatecken:
with open("input.txt") as src, open("output.txt", "w") as dst:
dst.write(src.read())
Likvärdigt med två nästlade with-block, men plattare. Hanterarna träds in från vänster till höger och avslutas i omvänd ordning; om __enter__ på den högra hanteraren utlöser ett undantag körs ändå den vänstra hanterarens __exit__.
2.24.2. Att skriva en kontexthanterare¶
Vilken klass som helst med metoderna __enter__ och __exit__ fungerar som en kontexthanterare:
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")
Utmatning:
--- setup ---
doing the work
--- end setup ---
__exit__ tar emot tre argument som beskriver undantaget som avslutade blocket, eller tre None-värden om blocket slutfördes normalt. Att returnera False (eller None) låter eventuella undantag fortplanta sig efter nedmonteringen; att returnera True skulle svälja det.
Använd kontexthanterare för alla resurser som har en livscykel av typen ”öppna / stäng” eller ”reservera / frigör” – inte bara filer. Mönstret håller uppstädning kopplad till uppstart på den punkt där båda introduceras, så ett bortglömt close mitt i en lång funktion kan inte läcka resursen.