logo

z izjavo v Pythonu

V Pythonu, z izjavo se uporablja pri obravnavanju izjem, da je koda čistejša in veliko bolj berljiva. Poenostavlja upravljanje skupnih virov, kot so datotečni tokovi. Upoštevajte naslednji primer kode o tem, kako uporaba stavka with naredi kodo čistejšo.

Python3




c++ set





# file handling> # 1) without using with statement> file> => open>(>'file_path'>,>'w'>)> file>.write(>'hello world !'>)> file>.close()> # 2) without using with statement> file> => open>(>'file_path'>,>'w'>)> try>:> >file>.write(>'hello world'>)> finally>:> >file>.close()>



>

>

Python3




# using with statement> with>open>(>'file_path'>,>'w'>) as>file>:> >file>.write(>'hello world !'>)>

>

>

Upoštevajte, da v nasprotju s prvima dvema implementacijama pri uporabi stavka with ni treba klicati file.close(). Sama izjava with zagotavlja pravilno pridobivanje in sprostitev virov. Izjema med klicem file.write() v prvi izvedbi lahko prepreči pravilno zapiranje datoteke, kar lahko povzroči več napak v kodi, tj. veliko sprememb v datotekah ne začne veljati, dokler datoteka ni pravilno zaprta. Drugi pristop v zgornjem primeru poskrbi za vse izjeme, vendar uporaba stavka with naredi kodo kompaktno in veliko bolj berljivo. Izjava with tako pomaga pri izogibanju napakam in uhajanju, saj zagotavlja, da je vir pravilno sproščen, ko je koda, ki uporablja vir, v celoti izvedena. Stavek with se pogosto uporablja z datotečnimi tokovi, kot je prikazano zgoraj, in s ključavnicami, vtičnicami, podprocesi in telneti itd.

Podpora stavku with v uporabniško definiranih objektih

Open() ni nič posebnega, zaradi česar bi bil uporaben s stavkom with, enako funkcionalnost pa je mogoče zagotoviti v uporabniško definiranih objektih. Podpora z izjavo v vaših objektih bo zagotovila, da nobenega vira nikoli ne pustite odprtega. Če želite uporabiti stavek with v uporabniško določenih objektih, morate dodati samo metodi __enter__() in __exit__() v objektne metode. Za dodatno pojasnilo si oglejte naslednji primer.

Python3




opozorilno polje javascript

string.format v Javi
# a simple file writer object> class> MessageWriter(>object>):> >def> __init__(>self>, file_name):> >self>.file_name>=> file_name> > >def> __enter__(>self>):> >self>.>file> => open>(>self>.file_name,>'w'>)> >return> self>.>file> >def> __exit__(>self>,>*>args):> >self>.>file>.close()> # using with statement with MessageWriter> with MessageWriter(>'my_file.txt'>) as xfile:> >xfile.write(>'hello world'>)>

>

>

Preglejmo zgornjo kodo. Če opazite, je tisto, kar sledi ključni besedi with, konstruktor za MessageWriter. Takoj ko izvedba vstopi v kontekst stavka with, se ustvari objekt MessageWriter in python nato pokliče metodo __enter__(). V tej metodi __enter__() inicializirajte vir, ki ga želite uporabiti v objektu. Ta metoda __enter__() mora vedno vrniti deskriptor pridobljenega vira. Kaj so deskriptorji virov? To so ročaji, ki jih nudi operacijski sistem za dostop do zahtevanih virov. V naslednjem bloku kode je datoteka deskriptor vira datotečnega toka.

Python




file> => open>(>'hello.txt'>)>

>

>

V zgornjem primeru MessageWriter metoda __enter__() ustvari deskriptor datoteke in ga vrne. Ime xfile se tukaj uporablja za sklicevanje na deskriptor datoteke, ki ga vrne metoda __enter__(). Blok kode, ki uporablja pridobljeni vir, je postavljen znotraj bloka stavka with. Takoj ko se izvede koda znotraj bloka with, se pokliče metoda __exit__(). Vsi pridobljeni viri se sprostijo v metodi __exit__(). Tako uporabljamo stavek with z uporabniško določenimi objekti. Ta vmesnik metod __enter__() in __exit__(), ki nudi podporo za stavek with v uporabniško definiranih objektih, se imenuje Upravitelj konteksta .

Modul contextlib

Upravljalnik konteksta, ki temelji na razredu, kot je prikazan zgoraj, ni edini način za podporo stavka with v uporabniško definiranih objektih. The contextlib modul ponuja še nekaj abstrakcij, zgrajenih na osnovnem vmesniku upravitelja konteksta. Tukaj je opisano, kako lahko prepišemo upravitelja konteksta za objekt MessageWriter z uporabo modula contextlib.

Python3




from> contextlib>import> contextmanager> class> MessageWriter(>object>):> >def> __init__(>self>, filename):> >self>.file_name>=> filename> >@contextmanager> >def> open_file(>self>):> >try>:> >file> => open>(>self>.file_name,>'w'>)> >yield> file> >finally>:> >file>.close()> # usage> message_writer>=> MessageWriter(>'hello.txt'>)> with message_writer.open_file() as my_file:> >my_file.write(>'hello world'>)>

pomenska napaka

>

>

V tem primeru kode zaradi donos v svoji definiciji je funkcija open_file() a funkcija generatorja . Ko je ta funkcija open_file() poklicana, ustvari deskriptor vira z imenom datoteka. Ta deskriptor vira se nato posreduje klicatelju in je tukaj predstavljen s spremenljivko my_file. Po izvedbi kode znotraj bloka with se programski nadzor vrne nazaj k funkciji open_file(). Funkcija open_file() nadaljuje z izvajanjem in izvede kodo, ki sledi stavku yield. Ta del kode, ki se pojavi po izjavi o donosu, sprosti pridobljene vire. @contextmanager tukaj je a dekorater . Prejšnja izvedba, ki temelji na razredu, in ta izvedba upraviteljev konteksta, ki temelji na generatorju, sta znotraj enaki. Čeprav se zadnje zdi bolj berljivo, zahteva znanje generatorjev, dekoraterjev in donosa.