Po raz pierwszy natknąłem się na with
instrukcję Python . Używam Pythona od kilku miesięcy i nawet nie wiedziałem o jego istnieniu! Biorąc pod uwagę jego nieco niejasny status, pomyślałem, że warto zapytać:
- Do czego służy instrukcja Python
with
? - Do czego tego używasz?
- Czy są jakieś problemy, o których muszę wiedzieć, lub powszechne anty-wzorce związane z ich użyciem? Jakieś przypadki, w których lepiej jest użyć
try..finally
niżwith
? - Dlaczego nie jest stosowany szerzej?
- Jakie standardowe klasy bibliotek są z nim zgodne?
with
w dokumentacji Python 3.Odpowiedzi:
Sądzę, że inni użytkownicy przede mną już na to odpowiedzieli, dlatego dodaję to tylko ze względu na kompletność:
with
oświadczenie upraszcza obsługę wyjątków, zamykając typowe zadania przygotowania i czyszczenia w tak zwanych menedżerach kontekstu . Więcej szczegółów można znaleźć w PEP 343 . Na przykładopen
instrukcja jest sama w sobie menedżerem kontekstu, który pozwala otworzyć plik, pozostawić otwarty, dopóki wykonanie jest w kontekściewith
instrukcji, w której go użyłeś, i zamknąć go, gdy tylko opuścisz kontekst, bez względu na to, czy go opuściłeś z powodu wyjątku, czy podczas regularnego przepływu kontroli.with
Oświadczenie może być więc wykorzystywane w sposób podobny do wzoru RAII w C ++ jakiś zasób jest nabywany przezwith
instrukcja i zwolniona, gdy opuściszwith
kontekst.Oto kilka przykładów: otwieranie plików za pomocą
with open(filename) as fp:
, uzyskiwanie blokad za pomocąwith lock:
(gdzielock
jest instancjathreading.Lock
). Możesz także zbudować własne menedżery kontekstu za pomocącontextmanager
dekoratora zcontextlib
. Na przykład często używam tego, gdy muszę tymczasowo zmienić bieżący katalog, a następnie wrócić do miejsca, w którym byłem:Oto kolejny przykład, który tymczasowo przekierowania
sys.stdin
,sys.stdout
asys.stderr
do innego uchwytu pliku i przywraca je później:I na koniec kolejny przykład, który tworzy folder tymczasowy i czyści go po opuszczeniu kontekstu:
źródło
with
instrukcja ma na celu wypełnienie zmiennej danymi, dopóki instrukcje w niej nie zostaną ukończone, a następnie zwolnić zmienną?with open('myScript.py', 'r') as f: pass
. Spodziewałem się, aby móc nazwać zmiennąf
aby zobaczyć treść tekstu dokumentu, jak to, co wydaje się, jeżeli dokument zostały przypisanef
poprzez regularneopen
oświadczenie:f = open('myScript.py').read()
. Ale zamiast tego mam następujący:<_io.TextIOWrapper name='myScript.py' mode='r' encoding='cp1252'>
. Co to znaczy?with
nie usuwa potrzebyread
rzeczywistego pliku. Dowith
rozmowyopen
- nie wie, co trzeba zrobić z nim - może chcesz zrobić szukać na przykład.with
Instrukcja może wypełnić zmienną danymi lub wprowadzić inne zmiany w środowisku, dopóki instrukcje w niej zawarte nie będą kompletne, a następnie przeprowadzi niezbędne czyszczenie. Rodzaje czyszczenia, które można wykonać, to na przykład zamknięcie otwartego pliku lub, jak w tym przykładzie @Tamas, zmiana katalogów z powrotem do poprzedniej lokalizacji itp. Ponieważ Python ma funkcje usuwania śmieci, zwolnienie zmiennej nie jest ważne przypadek użycia.with
jest zwykle używany do innych rodzajów czyszczenia.Sugerowałbym dwa ciekawe wykłady:
1.
with
stwierdzenie jest stosowany do zawijania wykonanie bloku z metod zdefiniowanych przez menedżera kontekstu. Umożliwiatry...except...finally
to enkapsulowanie typowych wzorców użytkowania w celu wygodnego ponownego użycia.2. Możesz zrobić coś takiego:
LUB
LUB (Python 3.1)
LUB
3. Nie widzę tu żadnego Antipattern.
Cytując Zanurz się w Pythonie :
4. Wydaje mi się, że jest to związane z nawykami programistów do używania
try..catch..finally
instrukcji z innych języków.źródło
with
.Instrukcja Python
with
jest wbudowaną obsługą językaResource Acquisition Is Initialization
idiomu powszechnie używanego w C ++. Ma on umożliwić bezpieczne pozyskiwanie i uwalnianie zasobów systemu operacyjnego.with
Instrukcja tworzy zasoby ramach zakresu / bloku. Pisz kod za pomocą zasobów w bloku. Po wyjściu z bloku zasoby są zwalniane bez względu na wynik kodu w bloku (tj. Czy blok kończy się normalnie, czy z powodu wyjątku).Wiele zasobów w bibliotece Python, które są zgodne z protokołem wymaganym przez
with
instrukcję i mogą być używane z nią od razu po wyjęciu z pudełka. Jednak każdy może tworzyć zasoby, które można wykorzystać w instrukcji with, poprzez wdrożenie dobrze udokumentowanego protokołu: PEP 0343Używaj go za każdym razem, gdy nabywasz zasoby w swojej aplikacji, które muszą zostać jawnie zrzeczone, takie jak pliki, połączenia sieciowe, blokady i tym podobne.
źródło
Ponownie dla kompletności dodam mój najbardziej użyteczny przypadek użycia
with
instrukcji.Robię dużo obliczeń naukowych i do niektórych czynności potrzebuję
Decimal
biblioteki do dowolnych obliczeń precyzji. Pewnej części mojego kodu potrzebuję wysokiej precyzji, a dla większości innych części potrzebuję mniejszej precyzji.Ustawiłem moją domyślną precyzję na niską liczbę, a następnie używam,
with
aby uzyskać bardziej precyzyjną odpowiedź dla niektórych sekcji:Używam tego bardzo często w teście hipergeometrycznym, który wymaga podziału dużych liczb wynikających z silni. Podczas wykonywania obliczeń w skali genomowej należy uważać na błędy zaokrąglania i przepełnienia.
źródło
Przykładem antipatternu może być użycie
with
wewnętrznej pętli, gdy bardziej efektywne byłoby posiadaniewith
zewnętrznej pętlina przykład
vs
Pierwszym sposobem jest otwieranie i zamykanie pliku dla każdego,
row
co może powodować problemy z wydajnością w porównaniu z drugim sposobem z otwieraniem i zamykaniem pliku tylko raz.źródło
Zobacz PEP 343 - Instrukcja „z” , na końcu znajduje się przykładowa sekcja.
źródło
punkty 1, 2 i 3 są odpowiednio uwzględnione:
4: jest stosunkowo nowy, dostępny tylko w python2.6 + (lub python2.5 przy użyciu
from __future__ import with_statement
)źródło
Instrukcja with działa z tak zwanymi menedżerami kontekstu:
http://docs.python.org/release/2.5.2/lib/typecontextmanager.html
Chodzi o to, aby uprościć obsługę wyjątków, wykonując niezbędne czyszczenie po opuszczeniu bloku „z”. Niektóre z wbudowanych Pythona działają już jako menedżery kontekstu.
źródło
Innym przykładem gotowej obsługi, który na początku może być nieco zaskakujący, gdy przyzwyczaisz się do zachowania wbudowanych
open()
, sąconnection
obiekty popularnych modułów bazy danych, takich jak:Te
connection
obiekty są menedżerowie kontekście i jako takie mogą być używane out-of-the-box w miłymwith-statement
, jednak przy stosowaniu tego pamiętać, że:Oznacza to, że programista musi zadbać o to, aby sam zamknął połączenie, ale pozwala uzyskać połączenie i używać go w wielu miejscach
with-statements
, jak pokazano w dokumentach psycopg2 :W powyższym przykładzie zauważysz, że
cursor
obiektamipsycopg2
są również menedżery kontekstu. Z odpowiedniej dokumentacji dotyczącej zachowania:źródło
W pythonie zazwyczaj używana jest instrukcja „ with ” do otwarcia pliku, przetworzenia danych zawartych w pliku, a także do zamknięcia pliku bez wywoływania metody close (). Instrukcja „with” upraszcza obsługę wyjątków, zapewniając czynności czyszczenia.
Ogólna forma z:
Uwaga: nie ma potrzeby zamykania pliku przez wywołanie close () po file-var.close ()
źródło