Jak prawidłowo ignorować wyjątki

776

Kiedy chcesz po prostu spróbować wypróbować bez obsługi wyjątku, jak to zrobić w Pythonie?

Czy podążanie za tym jest właściwym sposobem?

try:
    shutil.rmtree(path)
except:
    pass
Joan Venge
źródło
10
Dziwne, że nikt do tej pory o tym nie wspominał (zrobiłem to w mojej odpowiedzi), ale dla tej konkretnej funkcji możesz po prostu to zrobić shutil.rmtree(path, ignore_errors=True). Nie dotyczy to jednak większości funkcji.
Aaron Hall
9
Ważna lektura, gdy myślisz o ignorowaniu wyjątków: Dlaczego „wyjątek: zaliczenie” jest złą praktyką programistyczną?
szturcha
3
Wyobraź sobie, że robisz to w prawdziwym życiu. spróbuj: get_cash ('1000 $) z wyjątkiem: pass # meh, prawdopodobnie będzie w porządku
Grokodile

Odpowiedzi:

1039
try:
    doSomething()
except: 
    pass

lub

try:
    doSomething()
except Exception: 
    pass

Różnica polega na tym, że pierwszy z nich będzie również złapać KeyboardInterrupt, SystemExiti takie rzeczy, które pochodzą bezpośrednio z exceptions.BaseExceptionnie exceptions.Exception.

Szczegółowe informacje można znaleźć w dokumentacji:

vartec
źródło
4
Zauważ, że StopIteration i Warning dziedziczą również od wyjątku. W zależności od potrzeb możesz zamiast tego odziedziczyć StandardError.
Ben Blank,
1
To prawda, ale jeśli nie jesteś ostrożny, możesz napotkać subtelne błędy (szczególnie jeśli robisz coś innego niż przekazywanie StopIteration).
Jason Baker
17
-1, try: shuti.rmtree(...) except: passz grubsza tłumi wszelkie błędy (nawet jeśli źle shutilNameErrorexcept OSError:
przeliterujesz,
44
W tej odpowiedzi, mimo że ma ona charakter informacyjny, brakuje ważnej informacji - nigdy nie należy wychwytywać wyjątku w ten sposób. Zamiast tego powinieneś zawsze starać się wychwycić tylko te wyjątki, na których ci zależy, w przeciwnym razie będziesz mieć koszmary podczas polowania na trywialne błędy, ukryte przez swoje ogólne „wyjątki”. Aby uzyskać więcej informacji, zobacz odpowiedź dbr. (Wiem, że to nie było oryginalne pytanie - ale każdy, kto tego szuka, po prostu weźmie swój fragment i użyje go w
niezmienionej
139

Najlepszą praktyką jest wychwytywanie tylko tych błędów, które Cię interesują. W przypadku shutil.rmtreeprawdopodobnie OSError:

>>> shutil.rmtree("/fake/dir")
Traceback (most recent call last):
    [...]
OSError: [Errno 2] No such file or directory: '/fake/dir'

Jeśli chcesz po cichu zignorować ten błąd, wykonaj następujące czynności:

try:
    shutil.rmtree(path)
except OSError:
    pass

Dlaczego? Powiedzmy, że przypadkowo przekazujesz funkcję liczby całkowitej zamiast ciągu, na przykład:

shutil.rmtree(2)

Daje błąd „TypeError: zmuszanie do Unicode: potrzebujesz ciągu lub bufora, znaleziono int” - prawdopodobnie nie chcesz tego ignorować, co może być trudne do debugowania.

Jeśli zdecydowanie chcesz zignorować wszystkie błędy, złap Exceptionraczej niż zwykłe except:oświadczenie. Znowu dlaczego?

Brak określenia wyjątku przechwytuje każdy wyjątek, w tym SystemExitwyjątek, który na przykład sys.exit()wykorzystuje:

>>> try:
...     sys.exit(1)
... except:
...     pass
... 
>>>

Porównaj to z następującymi, które poprawnie wychodzą:

>>> try:
...     sys.exit(1)
... except Exception:
...     pass
... 
shell:~$ 

Jeśli chcesz pisać coraz lepiej zachowujący się kod, OSErrorwyjątek może reprezentować różne błędy, ale w powyższym przykładzie chcemy tylko zignorować Errno 2, abyśmy mogli być jeszcze bardziej szczegółowi:

import errno

try:
    shutil.rmtree(path)
except OSError as e:
    if e.errno != errno.ENOENT:
        # ignore "No such file or directory", but re-raise other errors
        raise
dbr
źródło
1
shutil.rmtreenie jest najlepszym przykładem, ponieważ po prostu ignore_errors=True
użyłbyś
113

Kiedy chcesz po prostu spróbować złapać bez obsługi wyjątku, jak to zrobić w Pythonie?

To zależy od tego, co rozumiesz przez „obsługę”.

Jeśli chcesz go złapać bez podejmowania jakichkolwiek działań, opublikowany kod będzie działał.

Jeśli masz na myśli, że chcesz podjąć działanie w stosunku do wyjątku bez zatrzymywania wyjątku przed wejściem na wyższy stos, to potrzebujesz czegoś takiego:

try:
    do_something()
except:
    handle_exception()
    raise  #re-raise the exact same exception that was thrown
Jason Baker
źródło
88

Najpierw zacytowałem odpowiedź Jacka O'Connora z tego wątku . Odwołany wątek został zamknięty, więc piszę tutaj:

„Jest nowy sposób na zrobienie tego w Pythonie 3.4:

from contextlib import suppress

with suppress(Exception):
    # your code

Oto zatwierdzenie, które go dodało: http://hg.python.org/cpython/rev/406b47c64480

A oto autor, Raymond Hettinger, mówiąc o tym i wielu innych upodobaniach Pythona: https://youtu.be/OSGv2VnC0go?t=43m23s

Mój dodatek do tego to odpowiednik Python 2.7:

from contextlib import contextmanager

@contextmanager
def ignored(*exceptions):
    try:
        yield
    except exceptions:
        pass

Następnie używasz go jak w Pythonie 3.4:

with ignored(Exception):
    # your code
Jabba
źródło
55

Dla pełności:

>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print("division by zero!")
...     else:
...         print("result is", result)
...     finally:
...         print("executing finally clause")

Pamiętaj również, że możesz przechwycić wyjątek w następujący sposób:

>>> try:
...     this_fails()
... except ZeroDivisionError as err:
...     print("Handling run-time error:", err)

... i ponownie podnieś wyjątek w ten sposób:

>>> try:
...     raise NameError('HiThere')
... except NameError:
...     print('An exception flew by!')
...     raise

... przykłady z samouczka języka python .

care
źródło
43

Jak poprawnie zignorować wyjątki?

Można to zrobić na kilka sposobów.

Jednak wybór przykładu ma proste rozwiązanie, które nie obejmuje ogólnego przypadku.

Specyficzny dla przykładu:

Zamiast

try:
    shutil.rmtree(path)
except:
    pass

Zrób to:

shutil.rmtree(path, ignore_errors=True)

Jest to argument specyficzny dla shutil.rmtree. Możesz zobaczyć pomoc na ten temat, wykonując następujące czynności, a zobaczysz, że może ona również umożliwiać działanie w przypadku błędów.

>>> import shutil
>>> help(shutil.rmtree)

Ponieważ dotyczy to tylko wąskiego przypadku przykładu, pokażę dalej, jak sobie z tym poradzić, jeśli te argumenty słów kluczowych nie istnieją.

Ogólne podejście

Ponieważ powyższe dotyczy tylko wąskiego przypadku przykładu, pokażę dalej, jak sobie z tym poradzić, jeśli te argumenty słów kluczowych nie istnieją.

Nowości w Python 3.4:

Możesz zaimportować suppressmenedżera kontekstu:

from contextlib import suppress

Ale tylko pomiń najbardziej specyficzny wyjątek:

with suppress(FileNotFoundError):
    shutil.rmtree(path)

Po cichu zignorujesz FileNotFoundError:

>>> with suppress(FileNotFoundError):
...     shutil.rmtree('bajkjbkdlsjfljsf')
... 
>>> 

Z dokumentów :

Podobnie jak w przypadku każdego innego mechanizmu, który całkowicie eliminuje wyjątki, ten menedżer kontekstu powinien być używany tylko do pokrywania bardzo specyficznych błędów, o których wiadomo, że cicho kontynuuje wykonywanie programu.

Zauważ, że suppressi FileNotFoundErrorsą dostępne tylko w Pythonie 3.

Jeśli chcesz, aby Twój kod działał również w Pythonie 2, zobacz następną sekcję:

Python 2 i 3:

Jeśli chcesz po prostu spróbować / oprócz bez obsługi wyjątku, jak to zrobić w Pythonie?

Czy podążanie za tym jest właściwym sposobem?

try :
    shutil.rmtree ( path )
except :
    pass

W przypadku kodu zgodnego z Python 2 passjest to poprawny sposób, aby uzyskać instrukcję, której nie można pominąć. Ale kiedy robisz gołe except:, że to samo, co robi except BaseException:, które zawiera GeneratorExit, KeyboardInterrupti SystemExit, w ogóle, nie chcesz, aby złapać te rzeczy.

W rzeczywistości powinieneś nazwać wyjątek tak dokładnie, jak możesz.

Oto część hierarchii wyjątków języka Python (2) i, jak widać, jeśli złapiesz bardziej ogólne wyjątki, możesz ukryć nieoczekiwane problemy:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StandardError
      |    +-- BufferError
      |    +-- ArithmeticError
      |    |    +-- FloatingPointError
      |    |    +-- OverflowError
      |    |    +-- ZeroDivisionError
      |    +-- AssertionError
      |    +-- AttributeError
      |    +-- EnvironmentError
      |    |    +-- IOError
      |    |    +-- OSError
      |    |         +-- WindowsError (Windows)
      |    |         +-- VMSError (VMS)
      |    +-- EOFError
... and so on

Prawdopodobnie chcesz złapać tutaj błąd OSErrr, a być może wyjątkiem, na którym ci nie zależy, jest brak katalogu.

Możemy uzyskać ten konkretny numer błędu z errnobiblioteki i poprawić go, jeśli go nie mamy:

import errno

try:
    shutil.rmtree(path)
except OSError as error:
    if error.errno == errno.ENOENT: # no such file or directory
        pass
    else: # we had an OSError we didn't expect, so reraise it
        raise 

Uwaga: nagie przebicie podnosi pierwotny wyjątek, który prawdopodobnie jest tym, czego chcesz w tym przypadku. Napisane bardziej zwięźle, ponieważ tak naprawdę nie musimy jawnie używać passkodu w obsłudze wyjątków:

try:
    shutil.rmtree(path)
except OSError as error:
    if error.errno != errno.ENOENT: # no such file or directory
        raise 
Aaron Hall
źródło
11

Kiedy chcesz po prostu spróbować złapać bez obsługi wyjątku, jak to zrobić w Pythonie?

Pomoże to wydrukować wyjątek :( tj. Spróbuj złapać bez obsługi wyjątku i wydrukować wyjątek).

import sys
try:
    doSomething()
except:
    print "Unexpected error:", sys.exc_info()[0]
Irengbam Tilokchan Singh
źródło
10
try:
      doSomething()
except Exception: 
    pass
else:
      stuffDoneIf()
      TryClauseSucceeds()

Do Twojej wiadomości klauzula else może przejść po wszystkich wyjątkach i zostanie uruchomiona tylko wtedy, gdy kod w try nie spowoduje wyjątku.

MrChrisRodriguez
źródło
1
Wreszcie dobre wyjaśnienie elsew tym kontekście. I dodać, że zawszefinally będzie działać po jakimkolwiek (lub bez wyjątku).
not2qubit
5

Musiałem zignorować błędy w wielu poleceniach i kurwa to załatwiło

import fuckit

@fuckit
def helper():
    print('before')
    1/0
    print('after1')
    1/0
    print('after2')

helper()
citynorman
źródło
+1, ponieważ zdecydowanie uczyniłeś mój dzień, ponieważ w tym kodzie źródłowym możesz nauczyć się bardzo przydatnych rzeczy, takich jak modyfikowanie stosu na żywo
WBAR
3

W Pythonie obsługujemy wyjątki podobne do innych języków, ale różnica polega na pewnej różnicy składni, na przykład:

try:
    #Your code in which exception can occur
except <here we can put in a particular exception name>:
    # We can call that exception here also, like ZeroDivisionError()
    # now your code
# We can put in a finally block also
finally:
    # Your code...
Deepak Kumar „SORTED”
źródło
-4

Zwykle po prostu robię:

try:
    doSomething()
except:
    _ = ""
Dylan Strudwick
źródło
3
Sugeruję, aby zamienić _ = ""z pass.
Legorooj