Jeśli chcesz dowiedzieć się więcej na ten temat niż odpowiedzi, Google połyka wyjątki. Oprócz nich możesz mieć wiele innych ciekawych nakazów i zakazów. Kod zapachy to kolejny.
Tony Hopkinson,
Odpowiedzi:
92
Prawie zawsze lepiej jest określić jawny typ wyjątku. Jeśli użyjesz except:klauzuli naked , możesz w końcu złapać wyjątki inne niż te, których się spodziewasz - może to ukryć błędy lub utrudnić debugowanie programów, które nie robią tego, czego się spodziewasz.
Na przykład, jeśli wstawiasz wiersz do bazy danych, możesz chcieć złapać wyjątek wskazujący, że wiersz już istnieje, aby można było przeprowadzić aktualizację.
Jeśli określisz bare except:, złapiesz również błąd gniazda wskazujący, że serwer bazy danych przewrócił się. Najlepiej jest wychwytywać tylko wyjątki, które wiesz, jak sobie z nimi radzić - często lepiej jest, aby program zakończył się niepowodzeniem w momencie wystąpienia wyjątku, niż kontynuował, ale zachowywał się w dziwny, nieoczekiwany sposób.
Jeden przypadek, w którym możesz chcieć użyć bare, except:znajduje się na najwyższym poziomie programu, który musisz zawsze uruchomić, na przykład serwera sieciowego. Ale wtedy musisz bardzo uważać, aby rejestrować wyjątki, w przeciwnym razie niemożliwe będzie ustalenie, co się dzieje. Zasadniczo w programie powinno być co najwyżej jedno miejsce, które to robi.
Konsekwencją tego wszystkiego jest to, że twój kod nigdy nie powinien działać, raise Exception('some message')ponieważ zmusza kod klienta do użycia except:(lub except Exception:co jest prawie tak samo złe). Powinieneś zdefiniować wyjątek specyficzny dla problemu, który chcesz zasygnalizować (może dziedziczyć z jakiejś wbudowanej podklasy wyjątków, takiej jak ValueErrorlub TypeError). Lub powinieneś zgłosić konkretny wbudowany wyjątek. Dzięki temu użytkownicy Twojego kodu mogą ostrożnie wychwytywać tylko wyjątki, które chcą obsłużyć.
+1 Bardzo prawdziwe. Jeszcze fajniej jest z przykładem: except:również łapie (między innymi) NameErrori AttributeError, więc jeśli źle przeliterujesz coś w trybloku (np. Twoja funkcja "wstaw" jest faktycznie wywoływana, insert_oneponieważ ktoś nie cenił spójności tak bardzo, jak powinien), zawsze po cichu próbuje update().
1
A co z sytuacją, gdy musisz upewnić się, że wyjątek nie zostanie wyrzucony nad bieżącą witryną wywołania? To znaczy - złapałem wszystkie specyficzne wyjątki, które mogę przewidzieć, teraz muszę dodać, że „jeśli coś, o czym nie myślałem, zostanie wyrzucone, muszę to zarejestrować, zanim zabije kontekst uruchomionego wykonywania” (na przykład main())?
Adam Parkin
Właśnie o takiej sytuacji mówię w akapicie rozpoczynającym się od „Jeden przypadek…”. Zdecydowanie jest to czasami potrzebne, ale każdy program powinien mieć tylko jedno miejsce, które to robi. I musisz uważać, aby w dzienniku było jasno widoczne, co się dzieje, w przeciwnym razie będziesz mieć frustrujący czas próbując zrozumieć, dlaczego Twój program nie obsługuje zdarzenia / żądania / czegokolwiek poprawnie.
babbageclunk
3
@delnan: Gorzej niż to. except Exception:złapie NameErrori AttributeErrorteż. Co sprawia, że gołą except:tak złe jest to, że rzeczy, które łapie ma żadnego interesu złowieniu, na przykład SystemExit(podniesione podczas rozmowy exitlub sys.exit, a teraz już zapobiec zamierzony exit) i KeyboardInterrupt(ponownie, jeśli przeboju użytkownika Ctrl-C, to prawdopodobnie nie chcą biec dalej tylko po to, by im złość). Tylko to ostatnie ma sens, aby złapać i powinno być złapane wyraźnie. Przynajmniej except Exception:pozwól tym dwóm rozmnażać się normalnie.
ShadowRanger
39
Nie należy ignorować rady udzielonej przez tłumacza.
Sama klauzula except: przechwytuje wyjątki SystemExit i KeyboardInterrupt, utrudniając przerwanie programu za pomocą Control-C i może maskować inne problemy. Jeśli chcesz wyłapać wszystkie wyjątki, które sygnalizują błędy programu, użyj wyjątku Exception: (bare except jest równoważne z wyjątkiem BaseException :).
Dobrą praktyczną zasadą jest ograniczenie używania samych klauzul „z wyjątkiem” do dwóch przypadków:
Jeśli program obsługi wyjątków będzie drukował lub logował śledzenie; przynajmniej użytkownik będzie świadomy wystąpienia błędu. Jeśli kod musi wykonać pewne prace porządkowe, ale pozwala na propagację wyjątku w górę za pomocą funkcji raise. spróbuj ... wreszcie może być lepszym sposobem załatwienia tej sprawy.
Istotą wyjątków jest zajęcie się problemem jak najbliżej miejsca jego powstania.
Zachowujesz więc kod, który w wyjątkowych okolicznościach może wywołać problem i rozwiązanie „obok” siebie.
Chodzi o to, że nie możesz znać wszystkich wyjątków, które mogą zostać wyrzucone przez fragment kodu. Jedyne, co możesz wiedzieć, to to, że jeśli jest to, powiedzmy, wyjątek nie znaleziono pliku, możesz go przechwycić i poprosić użytkownika o uzyskanie takiego, który wykonuje lub anuluje tę funkcję.
Jeśli umieścisz spróbuj złapać, to bez względu na to, jaki problem wystąpił w twojej procedurze pliku (tylko do odczytu, uprawnienia, UAC, nie do końca pdf, itp.), Każdy z nich wpadnie do twojego pliku nie znaleziono catch, a twój użytkownik krzyczy „ale jest, ten kod jest gówniany”
Teraz jest kilka sytuacji, w których możesz złapać wszystko, ale należy je wybierać świadomie.
Są przechwytywane, cofają jakąś akcję lokalną (taką jak tworzenie lub blokowanie zasobu (na przykład otwieranie pliku na dysku w celu zapisu), a następnie ponownie zgłaszasz wyjątek, aby zająć się nim na wyższym poziomie)
Drugi ty nie obchodzi cię, dlaczego poszło źle. Na przykład drukowanie. Możesz mieć cały haczyk, aby powiedzieć, że jest jakiś problem z twoją drukarką, napraw go i nie zabijaj aplikacji z tego powodu. Podobnie na próżno, gdyby twój kod wykonywał serię oddzielnych zadań używając jakiegoś harmonogramu, nie chciałbyś, żeby cała rzecz umarła, ponieważ jedno z zadań się nie powiodło.
Uwaga Jeśli wykonasz powyższe, nie mogę polecić jakiegoś rodzaju rejestrowania wyjątków, np. Spróbuj złapać koniec dziennika, wystarczająco wysoko.
Powiedziałbym, że chodzi o równowagę. Musisz złapać wyjątek wystarczająco wcześnie, aby móc się z niego zregenerować i wystarczająco późno, aby wiedzieć, gdzie się z nim udać. Dlatego obsługa wyjątków w Javie powoduje takie spustoszenie, ponieważ musisz ponownie zawijać wyjątek na każdym kroku i tracisz informacje.
dhill
2
+1 za „nie obchodzi cię, dlaczego poszło źle”. Używam go w kilku miejscach wokół jednego wiersza kodu, w którym analizuję datę / godzinę z adresu URL. Biblioteka analizująca datę / godzinę innej firmy nie zawiera wszystkich wyjątków, które może zgłosić (oprócz standardowego ValueError znalazłem OverflowError i TypeError, ale prawdopodobnie jest ich więcej), a poza tym naprawdę nie obchodzi mnie dlaczego został zgłoszony wyjątek, chcę po prostu przekazać użytkownikowi rozsądny komunikat o błędzie, informujący, że coś jest nie tak z datą / godziną.
Michael Rodby,
3
Z tym też złapiesz np. Control-C, więc nie rób tego, chyba że ponownie nim „rzucisz”. Jednak w takim przypadku powinieneś raczej użyć „w końcu”.
czy użycie except Exception:omija powyższe typy, których nie chcemy złapać?
HorseloverFat
except Exceptionjest w porządku.
Ulrich Eckhardt
4
@HorseloverFat: except Exceptionłapie SyntaxErrori MemoryErrorponieważ jest to ich klasa bazowa. KeyboardInterrupt, SystemExit(podniesione przez sys.exit()) nie są przechwytywane (są to bezpośrednie podklasy BaseException)
jfs
brzmi, jakby to nie było idealne - lepiej sprecyzować.
HorseloverFat
3
Oto miejsca, w których używam, z wyjątkiem bez typu
szybkie i brudne prototypowanie
To jest główne zastosowanie w moim kodzie dla niezaznaczonych wyjątków
funkcja main () najwyższego poziomu, w której rejestruję każdy niezłapany wyjątek
Zawsze to dodaję, aby kod produkcyjny nie wylewał śladów stosu
między warstwami aplikacji
Mam na to dwa sposoby:
Pierwszy sposób: gdy warstwa wyższego poziomu wywołuje funkcję niższego poziomu, zawija wywołania wpisanymi wyjątkami, aby obsłużyć wyjątki „najwyższego” niższego poziomu. Ale dodaję ogólną instrukcję except, aby wykryć nieobsłużone wyjątki niższego poziomu w funkcjach niższego poziomu.
Wolę to w ten sposób, łatwiej jest mi wykryć, które wyjątki powinny zostać odpowiednio przechwycone: „widzę” problem lepiej, gdy wyjątek niższego poziomu jest rejestrowany przez wyższy poziom
Drugi sposób: każda funkcja najwyższego poziomu warstw niższego poziomu ma swój kod zawinięty w ogólny, z wyjątkiem tego, że przechwytuje wszystkie nieobsługiwane wyjątki na tej określonej warstwie.
Niektórzy współpracownicy wolą ten sposób, ponieważ zachowuje on wyjątki niższego poziomu w funkcjach niższego poziomu, do których „należą”.
Odpowiedzi:
Prawie zawsze lepiej jest określić jawny typ wyjątku. Jeśli użyjesz
except:
klauzuli naked , możesz w końcu złapać wyjątki inne niż te, których się spodziewasz - może to ukryć błędy lub utrudnić debugowanie programów, które nie robią tego, czego się spodziewasz.Na przykład, jeśli wstawiasz wiersz do bazy danych, możesz chcieć złapać wyjątek wskazujący, że wiersz już istnieje, aby można było przeprowadzić aktualizację.
try: insert(connection, data) except: update(connection, data)
Jeśli określisz bare
except:
, złapiesz również błąd gniazda wskazujący, że serwer bazy danych przewrócił się. Najlepiej jest wychwytywać tylko wyjątki, które wiesz, jak sobie z nimi radzić - często lepiej jest, aby program zakończył się niepowodzeniem w momencie wystąpienia wyjątku, niż kontynuował, ale zachowywał się w dziwny, nieoczekiwany sposób.Jeden przypadek, w którym możesz chcieć użyć bare,
except:
znajduje się na najwyższym poziomie programu, który musisz zawsze uruchomić, na przykład serwera sieciowego. Ale wtedy musisz bardzo uważać, aby rejestrować wyjątki, w przeciwnym razie niemożliwe będzie ustalenie, co się dzieje. Zasadniczo w programie powinno być co najwyżej jedno miejsce, które to robi.Konsekwencją tego wszystkiego jest to, że twój kod nigdy nie powinien działać,
raise Exception('some message')
ponieważ zmusza kod klienta do użyciaexcept:
(lubexcept Exception:
co jest prawie tak samo złe). Powinieneś zdefiniować wyjątek specyficzny dla problemu, który chcesz zasygnalizować (może dziedziczyć z jakiejś wbudowanej podklasy wyjątków, takiej jakValueError
lubTypeError
). Lub powinieneś zgłosić konkretny wbudowany wyjątek. Dzięki temu użytkownicy Twojego kodu mogą ostrożnie wychwytywać tylko wyjątki, które chcą obsłużyć.źródło
except:
również łapie (między innymi)NameError
iAttributeError
, więc jeśli źle przeliterujesz coś wtry
bloku (np. Twoja funkcja "wstaw" jest faktycznie wywoływana,insert_one
ponieważ ktoś nie cenił spójności tak bardzo, jak powinien), zawsze po cichu próbujeupdate()
.main()
)?except Exception:
złapieNameError
iAttributeError
też. Co sprawia, że gołąexcept:
tak złe jest to, że rzeczy, które łapie ma żadnego interesu złowieniu, na przykładSystemExit
(podniesione podczas rozmowyexit
lubsys.exit
, a teraz już zapobiec zamierzony exit) iKeyboardInterrupt
(ponownie, jeśli przeboju użytkownikaCtrl-C
, to prawdopodobnie nie chcą biec dalej tylko po to, by im złość). Tylko to ostatnie ma sens, aby złapać i powinno być złapane wyraźnie. Przynajmniejexcept Exception:
pozwól tym dwóm rozmnażać się normalnie.Nie należy ignorować rady udzielonej przez tłumacza.
Z przewodnika po stylu PEP-8 dla Pythona:
try: import platform_specific_module except ImportError: platform_specific_module = None
źródło
except BaseException
nie oznacza tego samego, coexcept
: w Pythonie 2; w Pythonie 2 można było wywołać klasy w starym stylu jako wyjątki, które nie dziedziczą poBaseException
.Nie dotyczy to Pythona.
Istotą wyjątków jest zajęcie się problemem jak najbliżej miejsca jego powstania.
Zachowujesz więc kod, który w wyjątkowych okolicznościach może wywołać problem i rozwiązanie „obok” siebie.
Chodzi o to, że nie możesz znać wszystkich wyjątków, które mogą zostać wyrzucone przez fragment kodu. Jedyne, co możesz wiedzieć, to to, że jeśli jest to, powiedzmy, wyjątek nie znaleziono pliku, możesz go przechwycić i poprosić użytkownika o uzyskanie takiego, który wykonuje lub anuluje tę funkcję.
Jeśli umieścisz spróbuj złapać, to bez względu na to, jaki problem wystąpił w twojej procedurze pliku (tylko do odczytu, uprawnienia, UAC, nie do końca pdf, itp.), Każdy z nich wpadnie do twojego pliku nie znaleziono catch, a twój użytkownik krzyczy „ale jest, ten kod jest gówniany”
Teraz jest kilka sytuacji, w których możesz złapać wszystko, ale należy je wybierać świadomie.
Są przechwytywane, cofają jakąś akcję lokalną (taką jak tworzenie lub blokowanie zasobu (na przykład otwieranie pliku na dysku w celu zapisu), a następnie ponownie zgłaszasz wyjątek, aby zająć się nim na wyższym poziomie)
Drugi ty nie obchodzi cię, dlaczego poszło źle. Na przykład drukowanie. Możesz mieć cały haczyk, aby powiedzieć, że jest jakiś problem z twoją drukarką, napraw go i nie zabijaj aplikacji z tego powodu. Podobnie na próżno, gdyby twój kod wykonywał serię oddzielnych zadań używając jakiegoś harmonogramu, nie chciałbyś, żeby cała rzecz umarła, ponieważ jedno z zadań się nie powiodło.
Uwaga Jeśli wykonasz powyższe, nie mogę polecić jakiegoś rodzaju rejestrowania wyjątków, np. Spróbuj złapać koniec dziennika, wystarczająco wysoko.
źródło
Z tym też złapiesz np. Control-C, więc nie rób tego, chyba że ponownie nim „rzucisz”. Jednak w takim przypadku powinieneś raczej użyć „w końcu”.
źródło
Zawsze określić typ wyjątku, istnieje wiele rodzajów nie chcesz złapać, jak
SyntaxError
,KeyboardInterrupt
,MemoryError
itpźródło
except Exception:
omija powyższe typy, których nie chcemy złapać?except Exception
jest w porządku.except Exception
łapieSyntaxError
iMemoryError
ponieważ jest to ich klasa bazowa.KeyboardInterrupt
,SystemExit
(podniesione przezsys.exit()
) nie są przechwytywane (są to bezpośrednie podklasy BaseException)Oto miejsca, w których używam, z wyjątkiem bez typu
To jest główne zastosowanie w moim kodzie dla niezaznaczonych wyjątków
Zawsze to dodaję, aby kod produkcyjny nie wylewał śladów stosu
Mam na to dwa sposoby:
Wolę to w ten sposób, łatwiej jest mi wykryć, które wyjątki powinny zostać odpowiednio przechwycone: „widzę” problem lepiej, gdy wyjątek niższego poziomu jest rejestrowany przez wyższy poziom
Niektórzy współpracownicy wolą ten sposób, ponieważ zachowuje on wyjątki niższego poziomu w funkcjach niższego poziomu, do których „należą”.
źródło
Spróbuj tego:
try: #code except ValueError: pass
Odpowiedź dostałem z tego linku, czy ktoś jeszcze napotkał ten problem Sprawdź to
źródło