Mam funkcję wywoływaną przez program główny:
try:
someFunction()
except:
print "exception happened!"
ale w trakcie wykonywania funkcji podnosi wyjątek, więc przeskakuje do except
części.
Jak mogę zobaczyć dokładnie, co się stało w tym, someFunction()
co spowodowało wyjątek?
except:
(bez gołyraise
), z wyjątkiem może raz na program, a najlepiej nie wtedy.except
klauzul, nie będziesz musiał sprawdzać typu wyjątku, co zwykle robi się, aby działać zgodnie z określonym typem wyjątku.except
bloku wyjątek jest dostępny poprzezsys.exc_info()
funkcję - ta funkcja zwraca krotkę trzech wartości, które dają informacje o aktualnie obsługiwanym wyjątku.Odpowiedzi:
Wszystkie pozostałe odpowiedzi wskazują, że nie należy wychwytywać ogólnych wyjątków, ale wydaje się, że nikt nie chce ci powiedzieć, dlaczego, co jest niezbędne do zrozumienia, kiedy możesz złamać „zasadę”. Oto wyjaśnienie. Zasadniczo jest tak, że nie ukrywasz:
Tak długo, jak dbasz o to, aby nie zrobić żadnej z tych rzeczy, możesz uchwycić ogólny wyjątek. Na przykład możesz podać użytkownikowi informacje o wyjątku w inny sposób, na przykład:
Jak więc złapać ogólny wyjątek? Istnieje kilka sposobów. Jeśli chcesz tylko obiekt wyjątku, zrób to w następujący sposób:
Zrobić pewny
message
jest zwrócenie uwagi użytkownika na dysku-do-miss sposób! Wydruk, jak pokazano powyżej, może nie wystarczyć, jeśli wiadomość jest zakopana w wielu innych wiadomościach. Brak zwrócenia uwagi użytkowników jest równoznaczny z połknięciem wszystkich wyjątków, a jeśli jest jedno wrażenie, które powinieneś odejść po przeczytaniu odpowiedzi na tej stronie, oznacza to, że nie jest to dobra rzecz . Zakończenie bloku wyjątkówraise
instrukcją rozwiąże problem poprzez przejrzyste powtórzenie wychwyconego wyjątku.Różnica między powyższym a używaniem
except:
bez żadnego argumentu jest dwojaka:except:
nie daje obiektu wyjątku do sprawdzeniaSystemExit
,KeyboardInterrupt
aGeneratorExit
nie są objęte powyższym kodzie, który jest zwykle to, co chcesz. Zobacz hierarchię wyjątków .Jeśli chcesz również uzyskać taki sam ślad stosu, jeśli nie złapiesz wyjątku, możesz uzyskać to w ten sposób (nadal wewnątrz klauzuli wyjątku):
Jeśli korzystasz z
logging
modułu, możesz wydrukować wyjątek do dziennika (wraz z komunikatem) w następujący sposób:Jeśli chcesz głębiej kopać i badać stos, przeglądać zmienne itp., Użyj
post_mortem
funkcjipdb
modułu wewnątrz bloku oprócz:Odkryłem, że ta ostatnia metoda jest nieoceniona podczas tropienia błędów.
źródło
Uzyskaj nazwę klasy, do której należy obiekt wyjątku:
a użycie funkcji print_exc () spowoduje także wydrukowanie śladu stosu, który jest niezbędną informacją dla każdego komunikatu o błędzie.
Lubię to:
Otrzymasz dane wyjściowe w następujący sposób:
Po wydrukowaniu i analizie kod może zdecydować, aby nie obsługiwać wyjątków i po prostu wykonać
raise
:Wynik:
I interpreter drukuje wyjątek:
Po
raise
oryginalnym wyjątku nadal propaguje się dalej w górę stosu wywołań. ( Uwaga na ewentualną pułapkę ) Jeśli podniesiesz nowy wyjątek, będzie to oznaczać nowy (krótszy) ślad stosu.Wynik:
Zauważ, że traceback nie obejmuje
calculate()
funkcji z linii,9
która jest źródłem oryginalnego wyjątkue
.źródło
traceback.format_exc()
takżee.__class__.__name__
czy to to samotype(e).__name__
, co sugeruje powyższa odpowiedź?Zwykle nie powinieneś wychwytywać wszystkich możliwych wyjątków,
try: ... except
ponieważ jest to zbyt szerokie. Po prostu złap te, które mają się wydarzyć z jakiegokolwiek powodu. Jeśli naprawdę musisz, na przykład jeśli chcesz dowiedzieć się więcej o problemach podczas debugowania, powinieneś to zrobićźródło
try: ... except Exception:
wielu rzeczy, np. Korzystania z bibliotek zależnych od sieci lub masażystki danych, która może wysyłać do niej dziwne rzeczy. Oczywiście mam też odpowiednie logowanie. Jest to niezbędne, aby program mógł kontynuować działanie w przypadku pojedynczego błędu w danych wejściowych.smtplib
?Chyba że
somefunction
jest to bardzo źle zakodowana starsza funkcja, nie powinieneś potrzebować tego, o co pytasz.Użyj wielu
except
klauzul do obsługi różnych wyjątków na różne sposoby:Chodzi przede wszystkim o to, że nie powinieneś wychwytywać ogólnego wyjątku, ale tylko te, które musisz. Jestem pewien, że nie chcesz ukrywać nieoczekiwanych błędów lub błędów.
źródło
Większość odpowiedzi wskazuje na
except (…) as (…):
składnię (słusznie), ale jednocześnie nikt nie chce rozmawiać o słoniu w pokoju, w którym słoń jestsys.exc_info()
funkcją. Z dokumentacji z sys modułu (podkreślenie moje):Myślę, że
sys.exc_info()
można to potraktować jako najbardziej bezpośrednią odpowiedź na pierwotne pytanie: skąd mam wiedzieć, jaki rodzaj wyjątku miał miejsce?źródło
except
. Ze względu na kompletnośćexctype, value = sys.exc_info()[:2]
poda typ wyjątku, który można następnie zastosować wexcept
.try: someFunction () oprócz Exception, exc:
źródło
exc.__class__.__name__
zostało już zasugerowane w odpowiedzi Alexa - stackoverflow.com/a/9824060/95735Odpowiedzi te nadają się do debugowania, ale przy programowym testowaniu wyjątku
isinstance(e, SomeException)
może być przydatne, ponieważ testuje również podklasySomeException
, dzięki czemu można tworzyć funkcje, które będą stosowane do hierarchii wyjątków.źródło
Oto jak radzę sobie z wyjątkami. Chodzi o to, aby spróbować rozwiązać problem, jeśli jest to łatwe, a następnie dodać bardziej pożądane rozwiązanie, jeśli to możliwe. Nie rozwiązuj problemu w kodzie, który generuje wyjątek, lub ten kod traci oryginalny algorytm, który należy zapisać od razu. Przekaż jednak dane potrzebne do rozwiązania problemu i zwróć lambda na wypadek, gdybyś nie mógł rozwiązać problemu poza kodem, który go generuje.
Na razie, ponieważ nie chcę myśleć stycznie do celu mojej aplikacji, nie dodałem żadnych skomplikowanych rozwiązań. Ale w przyszłości, gdy będę wiedział więcej o możliwych rozwiązaniach (ponieważ aplikacja jest bardziej zaprojektowana), mógłbym dodać słownik rozwiązań indeksowanych według
during
.W pokazanym przykładzie jednym z rozwiązań może być poszukiwanie danych aplikacji przechowywanych gdzie indziej, np. Jeśli plik „app.p” został przypadkowo usunięty.
Na razie, ponieważ pisanie procedury obsługi wyjątków nie jest mądrym pomysłem (nie znamy jeszcze najlepszych sposobów jej rozwiązania, ponieważ projekt aplikacji będzie ewoluować), po prostu zwracamy łatwą poprawkę, która działa tak, jakbyśmy działali aplikacja po raz pierwszy (w tym przypadku).
źródło
Aby dodać do odpowiedzi Lauritza, stworzyłem dekorator / opakowanie do obsługi wyjątków i dzienniki opakowań, które typy wyjątków wystąpiły.
Można to wywołać w metodzie klasy lub samodzielnej funkcji z dekoratorem:
@ moduł obsługi_ogólnej
Zobacz mój blog na pełny przykład: http://ryaneirwin.wordpress.com/2014/05/31/python-decorators-and-exception-handling/
źródło
Możesz zacząć zgodnie z zaleceniami Lauritza:
a potem po prostu to
print ex
lubię:źródło
Rzeczywisty wyjątek można zarejestrować w następujący sposób:
Możesz dowiedzieć się więcej o wyjątkach z Samouczka Python .
źródło
Twoje pytanie brzmi: „Jak dokładnie zobaczyć, co się stało w funkcji SomeFunction (), która spowodowała wyjątek?”
Wydaje mi się, że nie pytasz o to, jak poradzić sobie z nieprzewidzianymi wyjątkami w kodzie produkcyjnym (przy założeniu wielu odpowiedzi), ale jak dowiedzieć się, co powoduje konkretny wyjątek podczas programowania.
Najprostszym sposobem jest użycie debugera, który może zatrzymać miejsce, w którym występuje nieprzechwycony wyjątek, najlepiej nie wychodząc, aby można było sprawdzić zmienne. Na przykład PyDev w otwartym środowisku IDE Eclipse może to zrobić. Aby włączyć to w Eclipse, otwórz perspektywę debugowania, wybierz
Manage Python Exception Breakpoints
zRun
menu i sprawdźSuspend on uncaught exceptions
.źródło
Po prostu powstrzymaj się od wyłapywania wyjątku, a informacja zwrotna, którą drukuje Python, powie ci, jaki wyjątek wystąpił.
źródło