V Pythone, s výpisom sa používa pri spracovaní výnimiek, aby bol kód čistejší a oveľa čitateľnejší. Zjednodušuje správu bežných zdrojov, ako sú prúdy súborov. Pozrite si nasledujúci príklad kódu o tom, ako použitie príkazu with robí kód čistejším.
Python3
užívateľské meno
# 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 !'>)> |
>
testovanie a typy testovania
>
Všimnite si, že na rozdiel od prvých dvoch implementácií nie je potrebné volať file.close() pri použití s príkazom. Samotný príkaz with zabezpečuje správne získanie a uvoľnenie zdrojov. Výnimka počas volania file.write() v prvej implementácii môže zabrániť správnemu uzavretiu súboru, čo môže spôsobiť niekoľko chýb v kóde, t. j. mnohé zmeny v súboroch sa prejavia až po správnom zatvorení súboru. Druhý prístup vo vyššie uvedenom príklade sa stará o všetky výnimky, ale pomocou príkazu with je kód kompaktný a oveľa čitateľnejší. S príkazom teda pomáha predchádzať chybám a únikom zabezpečením správneho uvoľnenia zdroja po úplnom spustení kódu, ktorý zdroj používa. Príkaz with sa bežne používa so súborovými prúdmi, ako je uvedené vyššie, a so zámkami, soketmi, podprocesmi a telnetmi atď.
Podpora príkazu with v objektoch definovaných používateľom
V open() nie je nič zvláštne, vďaka čomu je použiteľné s príkazom with a rovnakú funkcionalitu možno poskytnúť aj v objektoch definovaných používateľom. Podpora pomocou príkazu vo vašich objektoch zaistí, že nikdy nenecháte žiadny zdroj otvorený. Na použitie s príkazom v užívateľom definovaných objektoch stačí pridať metódy __enter__() a __exit__() do objektových metód. Pre ďalšie objasnenie zvážte nasledujúci príklad.
Python3
# 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'>)> |
>
ascii tabuľka java
>
Pozrime sa na vyššie uvedený kód. Ak si všimnete, po kľúčovom slove with je konštruktor MessageWriter. Hneď ako spustenie vstúpi do kontextu príkazu with, vytvorí sa objekt MessageWriter a python potom zavolá metódu __enter__(). V tejto metóde __enter__() inicializujte zdroj, ktorý chcete použiť v objekte. Táto metóda __enter__() by mala vždy vrátiť deskriptor získaného zdroja. Čo sú deskriptory zdrojov? Toto sú rukoväte poskytované operačným systémom na prístup k požadovaným prostriedkom. V nasledujúcom bloku kódu je súbor deskriptorom zdroja toku súborov.
Python
file> => open>(>'hello.txt'>)> |
>
>
Vo vyššie uvedenom príklade MessageWriter metóda __enter__() vytvorí deskriptor súboru a vráti ho. Názov xfile sa tu používa na označenie deskriptora súboru vráteného metódou __enter__(). Blok kódu, ktorý používa získaný zdroj, sa umiestni do bloku príkazu with. Hneď ako sa vykoná kód v bloku with, zavolá sa metóda __exit__(). Všetky získané zdroje sa uvoľnia metódou __exit__(). Takto používame príkaz with s užívateľsky definovanými objektmi. Toto rozhranie metód __enter__() a __exit__(), ktoré poskytuje podporu príkazu with v užívateľsky definovaných objektoch, sa nazýva Kontextový manažér .
dátové štruktúry java
Modul contextlib
Kontextový manažér založený na triedach, ako je uvedené vyššie, nie je jediným spôsobom, ako podporiť príkaz with v objektoch definovaných používateľom. The contextlib modul poskytuje niekoľko ďalších abstrakcií postavených na základnom rozhraní kontextového manažéra. Tu je návod, ako môžeme prepísať kontextového manažéra pre objekt MessageWriter pomocou modulu 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'>)> |
>
>
V tomto príklade kódu kvôli výnos vo svojej definícii je funkcia open_file() a funkcia generátora . Keď sa zavolá táto funkcia open_file(), vytvorí deskriptor prostriedku s názvom súbor. Tento deskriptor prostriedku sa potom odovzdá volajúcemu a je tu reprezentovaný premennou my_file. Po vykonaní kódu v bloku with sa riadenie programu vráti späť k funkcii open_file(). Funkcia open_file() obnoví svoje vykonávanie a spustí kód nasledujúci po príkaze výnosu. Táto časť kódu, ktorá sa objaví po výpise výnosov, uvoľňuje získané zdroje. @contextmanager tu je a dekoratér . Predchádzajúca implementácia založená na triedach a táto implementácia kontextových manažérov založená na generátore je vnútorne rovnaká. Zatiaľ čo neskoršie sa zdá byť čitateľnejšie, vyžaduje znalosť generátorov, dekoratérov a výnosu.