Come ignorare correttamente le eccezioni


777

Quando vuoi solo fare un tentativo-salvo senza gestire l'eccezione, come lo fai in Python?

Il seguente è il modo giusto per farlo?

try:
    shutil.rmtree(path)
except:
    pass

10
Strano che nessuno lo abbia menzionato finora (l'ho fatto nella mia risposta), ma per questa funzione specifica, puoi semplicemente farlo shutil.rmtree(path, ignore_errors=True). Questo non si applica alla maggior parte delle funzioni, tuttavia.
Aaron Hall

9
Lettura importante quando si pensa di ignorare le eccezioni: Perché "tranne: passare" è una cattiva pratica di programmazione?
colpì il

3
Immagina di farlo nella vita reale. provare: get_cash ('$ 1000') tranne: pass # meh, probabilmente andrà bene
Grokodile,

Vita reale:try: rob() except: run()
PatrickT

Risposte:


1039
try:
    doSomething()
except: 
    pass

o

try:
    doSomething()
except Exception: 
    pass

La differenza è che anche il primo prenderà KeyboardInterrupt, SystemExite cose del genere, che sono derivate direttamente exceptions.BaseException, non exceptions.Exception.

Vedi la documentazione per i dettagli:


4
Nota che StopIteration e Warning ereditano entrambi anche da Exception. A seconda delle tue esigenze, potresti invece voler ereditare da StandardError.
Ben Blank,

1
Questo è vero, ma se non stai attento, puoi imbatterti in bug sottili (specialmente se stai facendo qualcosa di diverso dal trasmettere StopIteration).
Jason Baker,

17
-1, try: shuti.rmtree(...) except: passsopprimerà grossolanamente qualsiasi errore (anche se si scrive shutilin modo errato con conseguente a NameError) - per lo meno fareexcept OSError:
dbr

44
Questa risposta, sebbene informativa, non contiene informazioni cruciali: non dovresti mai prendere un'eccezione in questo modo. Invece, dovresti sempre cercare di cogliere solo le eccezioni che ti interessano, altrimenti avrai incubi quando ti darai la caccia a bug insignificanti, nascosti dai tuoi generici "tranne". Vedi la risposta di dbr per maggiori informazioni. (So ​​che questa non era la domanda originale, ma chiunque cerchi questo prenderà il tuo frammento e lo userà così com'è)
johndodo,

139

È generalmente considerata la migliore pratica per catturare solo gli errori che ti interessano. Nel caso shutil.rmtreeprobabilmente è OSError:

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

Se si desidera ignorare silenziosamente tale errore, è necessario:

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

Perché? Di 'che (in qualche modo) passi accidentalmente la funzione un numero intero anziché una stringa, come:

shutil.rmtree(2)

Verrà visualizzato l'errore "TypeError: coercing a Unicode: need string o buffer, int found" - probabilmente non vorrai ignorarlo, che può essere difficile da eseguire il debug.

Se vuoi assolutamente ignorare tutti gli errori, prendi Exceptionpiuttosto che una semplice except:dichiarazione. Ancora una volta, perché?

Non specificando un'eccezione viene catturata ogni eccezione, inclusa l' SystemExiteccezione che ad esempio sys.exit()utilizza:

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

Confronta questo con il seguente, che esce correttamente:

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

Se vuoi scrivere un codice che si comporta sempre meglio, l' OSErroreccezione può rappresentare vari errori, ma nell'esempio sopra vogliamo solo ignorare Errno 2, quindi potremmo essere ancora più specifici:

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

1
shutil.rmtreenon è il miglior esempio, perché useresti solo ignore_errors=Trueper quella funzione ..
mercoledì

113

Quando vuoi solo provare a catturare senza gestire l'eccezione, come lo fai in Python?

Dipende da cosa intendi per "manipolazione".

Se intendi catturarlo senza intraprendere alcuna azione, il codice che hai pubblicato funzionerà.

Se vuoi dire che vuoi agire su un'eccezione senza fermare l'eccezione dallo stack, allora vuoi qualcosa del genere:

try:
    do_something()
except:
    handle_exception()
    raise  #re-raise the exact same exception that was thrown

88

Innanzitutto cito la risposta di Jack o'Connor da questa discussione . Il thread di riferimento è stato chiuso, quindi scrivo qui:

"C'è un nuovo modo per farlo in arrivo in Python 3.4:

from contextlib import suppress

with suppress(Exception):
    # your code

Ecco il commit che lo ha aggiunto: http://hg.python.org/cpython/rev/406b47c64480

Ed ecco l'autore, Raymond Hettinger, che parla di questo e di tutti gli altri tipi di hot di Python: https://youtu.be/OSGv2VnC0go?t=43m23s

La mia aggiunta a questo è l'equivalente di Python 2.7:

from contextlib import contextmanager

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

Quindi lo usi come in Python 3.4:

with ignored(Exception):
    # your code

55

Per completezza:

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

Si noti inoltre che è possibile acquisire l'eccezione in questo modo:

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

... e aumentare nuovamente l'eccezione in questo modo:

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

... esempi dal tutorial di Python .


43

Come ignorare correttamente le eccezioni?

Esistono diversi modi per farlo.

Tuttavia, la scelta dell'esempio ha una soluzione semplice che non copre il caso generale.

Specifico per l'esempio:

Invece di

try:
    shutil.rmtree(path)
except:
    pass

Fai questo:

shutil.rmtree(path, ignore_errors=True)

Questo è un argomento specifico per shutil.rmtree. Puoi vedere l'aiuto su di esso procedendo come segue e vedrai che può anche consentire funzionalità su errori.

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

Dal momento che questo copre solo il caso ristretto dell'esempio, dimostrerò ulteriormente come gestirlo se tali argomenti di parole chiave non esistessero.

Approccio generale

Poiché quanto sopra copre solo il caso ristretto dell'esempio, dimostrerò ulteriormente come gestirlo se tali argomenti di parole chiave non esistessero.

Novità in Python 3.4:

Puoi importare il suppressgestore del contesto:

from contextlib import suppress

Ma elimina solo l'eccezione più specifica:

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

Ignorerai silenziosamente un FileNotFoundError:

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

Dai documenti :

Come con qualsiasi altro meccanismo che sopprime completamente le eccezioni, questo gestore di contesto dovrebbe essere usato solo per coprire errori molto specifici in cui è noto che continuare silenziosamente con l'esecuzione del programma sia la cosa giusta da fare.

Si noti che suppresse FileNotFoundErrorsono disponibili solo in Python 3.

Se vuoi che il tuo codice funzioni anche in Python 2, consulta la sezione successiva:

Python 2 e 3:

Quando vuoi semplicemente provare / tranne senza gestire l'eccezione, come lo fai in Python?

Il seguente è il modo giusto per farlo?

try :
    shutil.rmtree ( path )
except :
    pass

Per il codice compatibile con Python 2, passè il modo corretto di avere un'istruzione che non è operativa. Ma quando si fa un nudo except:, che è lo stesso di fare except BaseException:, che comprende GeneratorExit, KeyboardInterrupte SystemExit, e, in generale, non si vuole per la cattura di queste cose.

In effetti, dovresti essere il più specifico possibile nel nominare l'eccezione.

Ecco parte della gerarchia delle eccezioni di Python (2) e, come puoi vedere, se ricevi eccezioni più generali, puoi nascondere i problemi che non ti aspettavi:

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

Probabilmente vuoi catturare un OSError qui, e forse l'eccezione che non ti interessa è se non c'è directory.

Possiamo ottenere quel numero di errore specifico dalla errnolibreria e rilanciare se non lo abbiamo:

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 

Nota, un semplice rilancio solleva l'eccezione originale, che è probabilmente quello che vuoi in questo caso. Scritto in modo più conciso, dal momento che non abbiamo davvero bisogno di esplicitamente passcon il codice nella gestione delle eccezioni:

try:
    shutil.rmtree(path)
except OSError as error:
    if error.errno != errno.ENOENT: # no such file or directory
        raise 

11

Quando vuoi solo provare a catturare senza gestire l'eccezione, come lo fai in Python?

Questo ti aiuterà a stampare qual è l'eccezione :( vale a dire provare a catturare senza gestire l'eccezione e stampare l'eccezione.)

import sys
try:
    doSomething()
except:
    print "Unexpected error:", sys.exc_info()[0]

10
try:
      doSomething()
except Exception: 
    pass
else:
      stuffDoneIf()
      TryClauseSucceeds()

Cordiali saluti la clausola else può andare dopo tutte le eccezioni e verrà eseguita solo se il codice nel tentativo non causa un'eccezione.


1
Finalmente una buona spiegazione elsein questo contesto. E per aggiungere che finallyverrà sempre eseguito dopo qualsiasi (o nessuna eccezione).
not2qubit

5

Avevo bisogno di ignorare gli errori in più comandi e cazzo ha fatto il trucco

import fuckit

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

helper()

+1 perché hai decisamente reso la mia giornata perché all'interno di questo codice sorgente puoi imparare alcune cose estremamente utili come modificare lo stack live
WBAR

3

In Python gestiamo eccezioni simili ad altre lingue, ma la differenza è una differenza di sintassi, ad esempio,

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...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.