Tak, The Zen of Python stwierdza "Mieszkanie jest lepsze niż zagnieżdżone", jednak nie jest to jedyna cecha, na której nam zależy; stwierdza również, że "Prostota jest lepsza niż złożona". Piękno with
polega na tym, że faktycznie przylega ona do zarówno tych zasad, co wyjaśnię poniżej.
Za każdym razem, gdy znajdujesz się w filozoficznym rozważaniu na temat funkcji w Pythonie, prawdopodobnie warto przejrzeć Python Enhancement Proposals (PEPs), aby przeczytać o motywacji tej funkcji. W tym przypadku PEP 343 -- The "with" Statement mówi się front w STRESZCZENIE:
Ten PEP dodaje nowe oświadczenie „z” do języka Python aby możliwy czynnik poza standardowe sposoby korzystania z try/finally wypowiedzi.
Faktoring out try/finally
wyciągi czyni kod prostszym i bardziej czytelnym.
PEP 343 idzie jednak głębiej niż dostarczanie uproszczonego cukru syntaktycznego. Ustanawia ona protokół menedżera kontekstu:
Wyrażenie natychmiast po z kluczowych w rachunku jest „wyrażenie kontekstu”, jak to wyrażenie stanowi główną wskazówkę jak do środowiska wykonawczego kierownik kontekst ustanawia dla czas trwania treści wyciągu.
Za pomocą protokołu menedżera kontekstu, programy piszące API mogą pomóc ukryć złożoność i zapewnić poprawne pozyskanie/uwolnienie zasobów w kontekście wielowątkowym.
Ale prawdziwe piękno rachunku with
jest pokazany w przykładzie 12 PEP 343 która wyjaśnia, że:
A „zagnieżdżone” kierownik kontekst, który automatycznie gniazduje dostarczonych konteksty od lewej do prawej, aby uniknąć nadmierne wcięcie.
Korzystanie kierownik nested()
kontekst można wziąć kod, który wygląda tak:
with a as x:
with b as y:
with c as z:
# Perform operation
i przekształcić go w ten sposób:
with nested(a, b, c) as (x, y, z):
# Perform operation
Zauważ, że nested()
został wprowadzony w Pythonie 2.5, ale od wersji 2.7 jest on przestarzały na korzyść tej wielokrotnej formy syntaktycznej menedżera kontekstu:
with a as x, b as y, c as z:
# Perform operation
Oczywiście nie tylko jest to prostsze i bardziej czytelne, ale jest znacznie bardziej płaskie niż zagnieżdżone. Zatem stosując with
jest po ścieżce 無爲 :)
UPDATE: W odpowiedzi na comments on Simeon Visser's answer Oto przykład, kiedy można używać wielu menedżerów kontekstowych, aby otworzyć więcej niż jeden plik na raz, gdy chcesz zip zawartość dwóch (lub więcej) plików ze sobą tak, że jeśli otwierając jeden z plików nie sprawi, że cała sprawa nie uda i prawidłowo zamknąć każdy plik, który został otworzony
from itertools import izip
with open("/etc/passwd") as a, open("/etc/group") as b, open("/etc/shadow") as c:
for lines in izip(a,b,c):
print map(lambda x: x.split(':')[0], lines)
uruchomić ten przykład dwa razy; raz jako root i raz jako zwykły użytkownik. Zakładając, że zapiszesz ten plik jako ziptogether.py
najpierw spróbujesz wywołać go jako root z sudo python ziptogether.py
i zakończy się pomyślnie, ale wywołanie go jako zwykłego użytkownika z python ziptogether.py
zakończy się niepowodzeniem, ponieważ nie masz uprawnień do odczytu /etc/shadow
. W przypadku niepowodzenia menedżer kontekstu upewni się, że pliki, które zostały pomyślnie otwarte przed niepowodzeniem, są poprawnie zamykane, gdy wykonywanie wykracza poza zakres oświadczenia with
.
W większości przypadków po prostu pozwoliłem IOError propagować i przechwytywać je gdzie indziej. – Dikei
Mimo że nie zgadzam się z przesłanką tego pytania, muszę dać ci rekwizyty, aby skłonić mnie do powrotu i ponownego przeczytania PEP [342] (http: //www.python.org/dev/peps/pep-0342 /) i [343] (http://www.python.org/dev/peps/pep-0343/) – kojiro