2.24. Kontekstinhallitsijat¶
with-lause suorittaa alustuskoodin, sitten rungon ja sitten purkukoodin – takeena, että purku suoritetaan, vaikka runko epäonnistuisi kesken kaiken. Metodiparia, joka tarjoaa alustuksen ja purun, kutsutaan kontekstinhallitsijaksi.
Muoto on:
with <expression> as <name>:
<body>
Lauseke palauttaa kontekstinhallitsijan. Python kutsuu sen __enter__-metodia, sitoo valinnaisesti tuloksen nimeen <name>, suorittaa rungon ja kutsuu sitten __exit__-metodia – riippumatta siitä, valmistuiko runko normaalisti vai nostiko se poikkeuksen.
__exit__ suoritetaan lohkon lopussa riippumatta siitä, mitä sen sisällä tapahtuu.¶
2.24.1. Kontekstinhallitsijan käyttäminen¶
Kanoninen esimerkki on tiedoston avaaminen:
with open("data.txt") as f:
text = f.read()
# f is now closed, even if read() failed
open() palauttaa tiedosto-olion, joka on itse kontekstinhallitsija; __enter__ palauttaa tiedoston ja __exit__ sulkee sen. with-lohko tekee ”sulje tiedosto aina, kun olet valmis” -toiminnasta oletusarvon sen sijaan, että kutsujan pitäisi muistaa se.
2.24.1.1. Useita kontekstinhallitsijoita¶
Yksittäinen with-lause voi siirtyä useaan kontekstinhallitsijaan kerralla, pilkuilla eroteltuina:
with open("input.txt") as src, open("output.txt", "w") as dst:
dst.write(src.read())
Vastaa kahta sisäkkäistä with-lohkoa, mutta on litteämpi. Hallitsijoihin siirrytään vasemmalta oikealle ja niistä poistutaan käänteisessä järjestyksessä; jos oikeanpuoleisen hallitsijan __enter__ nostaa poikkeuksen, vasemmanpuoleisen hallitsijan __exit__ suoritetaan silti.
2.24.2. Kontekstinhallitsijan kirjoittaminen¶
Mikä tahansa luokka, jolla on __enter__- ja __exit__-metodit, toimii kontekstinhallitsijana:
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")
Tuloste:
--- setup ---
doing the work
--- end setup ---
__exit__ saa kolme argumenttia, jotka kuvaavat lohkon päättäneen poikkeuksen, tai kolme None-arvoa, jos lohko valmistui normaalisti. Arvon False (tai None) palauttaminen antaa minkä tahansa poikkeuksen edetä purkamisen jälkeen; arvon True palauttaminen nielaisisi sen.
Käytä kontekstinhallitsijoita mihin tahansa resurssiin, jolla on ”avaa / sulje”- tai ”varaa / vapauta” -elinkaari – ei vain tiedostoihin. Malli pitää siivouksen pariutettuna alustuksen kanssa siinä kohdassa, jossa molemmat esitellään, joten unohtunut sulkeminen keskellä pitkää funktiota ei voi vuotaa resurssia.