Ku mojemu wstydowi nie mogę wymyślić, jak obsługiwać wyjątek dla instrukcji python „with”. Jeśli mam kod:
with open("a.txt") as f:
print f.readlines()
Naprawdę chcę obsłużyć „wyjątek braku pliku”, aby coś zrobić. Ale nie umiem pisać
with open("a.txt") as f:
print f.readlines()
except:
print 'oops'
i nie mogę pisać
with open("a.txt") as f:
print f.readlines()
else:
print 'oops'
dołączanie „z” w instrukcji try / else nie działa inaczej: wyjątek nie jest zgłaszany. Co mogę zrobić, aby przetworzyć awarię w instrukcji „with” w języku Python?
python
exception-handling
grigoryvp
źródło
źródło
with
Oświadczenie nie magicznie złamać otaczającątry...except
oświadczenie.Odpowiedzi:
Jeśli chcesz zastosować inną obsługę błędów niż otwarte połączenie niż działający kod, możesz:
źródło
try...except
bloki wewnątrz,with
aby być bliżej źródła wyjątku, który nie ma nic wspólnegoopen()
.Najlepszy „Pythoński” sposób, w jaki można to zrobić, wykorzystując
with
instrukcję, wymieniono jako przykład nr 6 w PEP 343 , który podaje tło instrukcji.Używany w następujący sposób:
źródło
try...except
instrukcji.Instrukcja with jest dostępna bez
__future__
importu od Python 2.6 . Możesz go pobrać już w Pythonie 2.5 (ale w tym momencie czas na aktualizację!) Dzięki:Oto najbliższa rzecz, którą możesz poprawić. Już prawie jesteś, ale
with
nie maszexcept
zdania:__exit__
Metoda menedżera kontekstu , jeśli zwróciFalse
, wyzeruje błąd po zakończeniu. Jeśli powróciTrue
, to go stłumi.open
Wbudowane to__exit__
nie wracaTrue
, więc wystarczy zagnieździć go w próbie, z wyjątkiem bloku:I standardowa płyta kotła: nie używaj gołej,
except:
która się chwytaBaseException
i każdego innego możliwego wyjątku i ostrzeżenia. Bądź co najmniej tak konkretny, jak wException
przypadku tego błędu, a może złapIOError
. Przechwytuj tylko błędy, na które jesteś przygotowany.W takim przypadku zrobiłbyś:
źródło
Rozróżnienie między możliwymi źródłami wyjątków zgłoszonych w
with
instrukcji złożonejRozróżnianie wyjątków występujących w
with
instrukcji jest trudne, ponieważ mogą pochodzić z różnych miejsc. Wyjątki można zgłaszać z jednego z następujących miejsc (lub wywoływanych tam funkcji):ContextManager.__init__
ContextManager.__enter__
with
ContextManager.__exit__
Aby uzyskać więcej informacji, zobacz dokumentację dotyczącą typów menedżera kontekstu .
Jeśli chcemy rozróżnić te różne przypadki, samo zawinięcie
with
w atry .. except
nie jest wystarczające. Rozważ następujący przykład (wykorzystującValueError
jako przykład, ale oczywiście można go zastąpić dowolnym innym typem wyjątku):Tutaj
except
wychwycą wyjątki pochodzące ze wszystkich czterech różnych miejsc, a zatem nie pozwalają na ich rozróżnienie. Jeśli przeniesiemy instancję obiektu menedżera kontekstu pozawith
, możemy rozróżnić__init__
iBLOCK / __enter__ / __exit__
:W rzeczywistości pomogło to w
__init__
części, ale możemy dodać dodatkową zmienną wartowniczą, aby sprawdzić, czy ciałowith
rozpoczęte do wykonania (tj. Rozróżnienie między__enter__
innymi):Trudna część polega na rozróżnieniu wyjątków pochodzących od
BLOCK
i__exit__
ponieważ wyjątek, który ucieka z treści,with
zostanie przekazany,__exit__
który może zdecydować, jak sobie z tym poradzić (zobacz dokumenty ). Jeśli jednak się__exit__
podniesie, oryginalny wyjątek zostanie zastąpiony nowym. Aby poradzić sobie z tymi przypadkami, możemy dodać wexcept
tekście ogólną klauzulę,with
aby zapisać każdy potencjalny wyjątek, który w przeciwnym razie uniknąłby niezauważenia, i porównać go z tym, który został schwytanyexcept
później w skrajnym otoczeniu - jeśli są one takie same, oznacza to, żeBLOCK
lub w inny sposób był__exit__
(w przypadku, gdy__exit__
tłumi wyjątek, zwracając prawdziwą wartość na zewnątrz)except
po prostu nie zostanie wykonany).Alternatywne podejście z wykorzystaniem równoważnej formy wymienionej w PEP 343
PEP 343 - Instrukcja „z” określa równoważną wersję
with
instrukcji „nie z” . Tutaj możemy łatwo owinąć różne części,try ... except
a tym samym rozróżnić różne potencjalne źródła błędów:Zwykle prostsze podejście wystarczy
Konieczność takiej specjalnej obsługi wyjątków powinny być bardzo rzadko i zwykle owinięcie całości
with
wtry ... except
bloku będzie wystarczająca. Zwłaszcza jeśli różne źródła błędów są wskazywane przez różne (niestandardowe) typy wyjątków (menedżery kontekstów muszą być odpowiednio zaprojektowane), możemy łatwo je rozróżnić. Na przykład:źródło