O wyłapywaniu KAŻDEGO wyjątku

697

Jak napisać try/ exceptblok, który przechwytuje wszystkie wyjątki?

użytkownik469652
źródło
4
W większości przypadków coś źle robisz, jeśli próbujesz złapać jakiś wyjątek. Mam na myśli, że możesz po prostu źle napisać coś w kodzie, a nawet nie będziesz o tym wiedział. Dobrą praktyką jest wychwytywanie określonych wyjątków.
vwvolodya
12
Mówiąc ściślej, wyłapanie wszystkich możliwych wyjątków stanowi problem tylko wtedy, gdy zostaną złapane w ciszy. Trudno wymyślić, gdzie indziej takie podejście jest właściwe, poza tym, gdzie wychwycone komunikaty o błędach są drukowane sys.stderri ewentualnie rejestrowane. To doskonale ważny i powszechny wyjątek.
Jewgienij Siergiejew
próbowałeś try: whatever() except Exception as e: exp_capture() :?
Charlie Parker

Odpowiedzi:

564

Możesz, ale prawdopodobnie nie powinieneś:

try:
    do_something()
except:
    print "Caught it!"

Będzie to jednak wychwytywało wyjątki takie jak KeyboardInterrupti zwykle tego nie chcesz, prawda? Chyba że od razu podniesiesz wyjątek - zobacz następujący przykład z dokumentacji :

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise
Tim Pietzcker
źródło
15
Twoje ostatnie stwierdzenie nie jest prawdziwe, musisz jawnie powiedzieć, except Exception:że goły, z wyjątkiem tego, że tam również złapie wyjątki BaseException.
Pykler
7
Naprawdę powinieneś wydrukować na stderr.
nyuszika7h
41
Bardzo, bardzo mocno nie zgadzam się ze stwierdzeniem „nie powinienem”. Powinieneś to robić oszczędnie. Są chwile, kiedy masz do czynienia z bibliotekami stron trzecich (czasami dynamicznie ładowanymi !!), które całkowicie oszalały z wyjątków, a ich prześledzenie może być bardzo bolesnym zadaniem, a jeśli przegapisz tylko jedną, masz bardzo, bardzo ogromny bolesny błąd w twoim systemie. To powiedziawszy, dobrze jest wyśledzić jak najwięcej i odpowiednio się z nimi obchodzić, a następnie mieć zapasowy haczyk dla tych, za którymi tęsknisz.
Blaze,
26
Dziwne jest również to, że w kaczym języku pisania, w którym nie deklarujesz zmiennych instancji, nagle bardzo martwi cię to, że nie wpisujesz wszystkich swoich wyjątków. Hmm!
Blaze,
837

Oprócz samej except:klauzuli (której, jak twierdzili inni, nie powinieneś używać), możesz po prostu złapać Exception:

import traceback
import logging

try:
    whatever()
except Exception as e:
    logging.error(traceback.format_exc())
    # Logs the error appropriately. 

Zwykle rozważasz zrobienie tego na zewnętrznym poziomie kodu, jeśli na przykład chcesz obsłużyć wszelkie nieprzechwycone wyjątki przed zakończeniem.

Zaletą except Exceptionnad gołą exceptjest to, że istnieje kilka wyjątków, których nie można złapać, oczywiścieKeyboardInterrupt i SystemExit: jeśli je złapałeś i połknąłeś, możesz utrudnić każdemu wyjście ze skryptu.

Duncan
źródło
Miałem to samo na myśli, ale jest to wada, przypuśćmy, że są to dwa błędy, gdy raz zostanie złapany, a poza tym, że tylko drukujesz, wyjdziesz z bloku prób i nigdy nie poznasz drugiego błędu. ,
6
Dla każdego, kto się zastanawia, całkowicie wbrew moim oczekiwaniom, to nadal będzie łapać niekluczowe podklasy takie jak ints, przynajmniej w python 2.x.
Joseph Garvin
5
@JosephGarvin, to jest niepoprawne, tzn. Nie złapie „wyjątków”, które nie podklasują Exception. Zauważ, że nie można zgłosić intwyjątku, a próba zrobienia tego powoduje TypeErrorwyjątek, który except Exceptionw takim przypadku zostałby złapany przez klauzulę załączającą . Z drugiej strony, klasę w starym stylu można podnieść i zakwalifikować jako „nie-wyjątek”, który nie zalicza się do podklasy Exception- zostanie przechwycona przez zwykłą exceptklauzulę, ale nie przez except Exceptionklauzulę.
Yoel,
4
@JosephGarvin sprawdź ten wpis na blogu: chris-lamb.co.uk/posts/no-one-expects-string-literal-exception Jestem z @Yoel na tym, twoje testy właśnie zamaskowałyTypeError
Duncan
2
@CharlieParker nie ma nic złego w łapaniu ich, jeśli tego właśnie chcesz, ale w większości nie. Wywołanie sys.exit()zwykle oznacza, że ​​oczekujesz zakończenia aplikacji, ale jeśli złapiesz SystemExit, nie nastąpi. Podobnie, jeśli naciśniesz Control-C na działającym skrypcie (Ctrl-break w systemie Windows), spodziewasz się, że program się zatrzyma, nie złapie błędu i nie przestanie działać. Ale możesz złapać jedno lub oba z nich, jeśli chcesz zrobić porządki przed ich istnieniem.
Duncan
100

Możesz to zrobić, aby obsłużyć ogólne wyjątki

try:
    a = 2/0
except Exception as e:
    print e.__doc__
    print e.message
vwvolodya
źródło
8
Może to nie obejmować wszystkich wyjątków, ponieważ klasą podstawową wszystkich wyjątków jest BaseException i napotkałem kod produkcyjny, który nie należy do rodziny klas Exception. Szczegółowe informacje na ten temat można znaleźć w docs.python.org/3/library/… .
DDay
4
To nie obejmuje wszystkich wyjątków.
Andy_A̷n̷d̷y̷
6
Technicznie powinien wyłapać wszystkie wyjątki nieobsługujące systemu. Z powiązanej dokumentacji @DDay: „ wyjątek BaseException: klasa bazowa dla wszystkich wbudowanych wyjątków. Nie jest przeznaczona do bezpośredniego dziedziczenia przez klasy zdefiniowane przez użytkownika (w tym celu należy użyć wyjątku)”. Jeśli nie pracujesz z kodem, który to ignoruje, lub nie musisz wychwytywać wyjątków wychodzących z systemu, powyższe powinno być w porządku.
Peter Cassetta
@PeterCassetta, kiedy ktoś chciałby złapać system wychodzący z wyjątków? Wydaje się, że wspólnym tematem w pytaniu jest to, że nie chcemy ich łapać, ale nie rozumiem dlaczego. Dlaczego nie zwykle?
Charlie Parker
68

Aby złapać wszystkie możliwe wyjątki, złap BaseException . Jest na szczycie hierarchii wyjątków:

Python 3: https://docs.python.org/3.5/library/exceptions.html#exception-hierarchy

Python 2.7: https://docs.python.org/2.7/library/exceptions.html#exception-hierarchy

try:
    something()
except BaseException as error:
    print('An exception occurred: {}'.format(error))

Ale jak wspomnieli inni, zwykle nie potrzebujesz tego, tylko w szczególnych przypadkach.

gitaarik
źródło
1
Czy pragnienie zapisania postępu długotrwałej pracy po naciśnięciu Ctrl-C jest tak niezwykłe?
BallpointBen
54

Bardzo prosty przykład, podobny do tego tutaj:

http://docs.python.org/tutorial/errors.html#defining-clean-up-actions

Jeśli próbujesz wyłapać WSZYSTKIE wyjątki, umieść cały kod w instrukcji „try:” zamiast „print”. Wykonanie czynności, która może spowodować wyjątek. ”.

try:
    print "Performing an action which may throw an exception."
except Exception, error:
    print "An exception was thrown!"
    print str(error)
else:
    print "Everything looks great!"
finally:
    print "Finally is called directly after executing the try statement whether an exception is thrown or not."

W powyższym przykładzie wynik byłby wyświetlany w następującej kolejności:

1) Wykonanie czynności, która może spowodować wyjątek.

2) Wreszcie wywoływany jest bezpośrednio po wykonaniu instrukcji try, niezależnie od tego, czy zgłoszony zostanie wyjątek.

3) „Zgłoszono wyjątek!” lub „Wszystko wygląda świetnie!” w zależności od tego, czy został zgłoszony wyjątek.

Mam nadzieję że to pomoże!

Joshua Burns
źródło
26

Można to zrobić na wiele sposobów, w szczególności w przypadku języka Python 3.0 i nowszych wersji

Podejście 1

Jest to proste podejście, ale niezalecane, ponieważ nie wiadomo dokładnie, który wiersz kodu zgłasza wyjątek:

def bad_method():
    try:
        sqrt = 0**-1
    except Exception as e:
        print(e)

bad_method()

Podejście 2

Takie podejście jest zalecane, ponieważ zapewnia więcej szczegółów na temat każdego wyjątku. Obejmuje:

  • Numer linii dla twojego kodu
  • Nazwa pliku
  • Rzeczywisty błąd w bardziej szczegółowy sposób

Jedyną wadą jest to, że tracback musi zostać zaimportowany.

import traceback

def bad_method():
    try:
        sqrt = 0**-1
    except Exception:
        print(traceback.print_exc())

bad_method()
grepit
źródło
21

Właśnie odkryłem tę małą sztuczkę do testowania nazw wyjątków w Pythonie 2.7. Czasami obsłużyłem określone wyjątki w kodzie, więc potrzebowałem testu, aby sprawdzić, czy ta nazwa znajduje się na liście obsługiwanych wyjątków.

try:
    raise IndexError #as test error
except Exception as e:
    excepName = type(e).__name__ # returns the name of the exception
Danilo
źródło
2
try:
    whatever()
except:
    # this will catch any exception or error

Warto wspomnieć, że nie jest to właściwe kodowanie w języku Python. Spowoduje to również wychwycenie wielu błędów, których możesz nie chcieć.

Yuval Adam
źródło
po prostu użyj z wyjątkiem nie buforuj wszystkich wyjątków, jak wspomniano w niektórych innych odpowiedziach. W tym celu musisz użyć wyjątku BaseException, ale jak powiedziałeś, nikt nie powinien wychwytywać wszystkich takich wyjątków. Wydaje mi się, że na początek jest ok, jeśli celem jest dodanie bardziej szczegółowego, z wyjątkiem okresu programowania, ale nie sądzę, że będzie ...
Pyglouthon