Cómo ignorar adecuadamente las excepciones

777

Cuando solo quieres probar, excepto sin manejar la excepción, ¿cómo lo haces en Python?

¿Es la siguiente la forma correcta de hacerlo?

try:
    shutil.rmtree(path)
except:
    pass
Joan Venge
fuente
10
Es extraño que nadie lo haya mencionado hasta ahora (lo hice en mi respuesta), pero para esta función específica, puedes hacerlo shutil.rmtree(path, ignore_errors=True). Sin embargo, esto no se aplicará a la mayoría de las funciones.
Aaron Hall
99
Lectura importante al pensar en ignorar las excepciones: ¿Por qué "excepto: pasar" es una mala práctica de programación?
empujar
3
Imagina hacer esto en la vida real. pruebe: get_cash ('$ 1000') excepto: pase # meh, probablemente estará bien
Grokodile
Vida real:try: rob() except: run()
PatrickT

Respuestas:

1039
try:
    doSomething()
except: 
    pass

o

try:
    doSomething()
except Exception: 
    pass

La diferencia es que el primero también atrapará KeyboardInterrupt, SystemExity cosas así, que se derivan directamente de exceptions.BaseException, no exceptions.Exception.

Consulte la documentación para más detalles:

vartec
fuente
44
Tenga en cuenta que StopIteration y Warning también heredan de Exception. Dependiendo de sus necesidades, es posible que desee heredar de StandardError en su lugar.
Ben Blank
1
Esto es cierto, pero si no tiene cuidado, puede encontrarse con errores sutiles (especialmente si está haciendo algo diferente a pasar StopIteration).
Jason Baker
17
-1, try: shuti.rmtree(...) except: passsuprimirá crudamente cualquier error (incluso si shutilNameErrorexcept OSError:
escribes
44
A esta respuesta, aunque informativa, le falta una información crucial: nunca debe detectar una excepción de esta manera. En su lugar, siempre debe tratar de atrapar solo las excepciones que le interesan, de lo contrario tendrá pesadillas al buscar errores triviales, ocultos por sus "excepto" genéricos. Vea la respuesta de dbr para más información. (Sé que esta no era la pregunta original, pero cualquiera que busque esto solo tomará su fragmento y lo usará como está)
johndodo
139

En general, se considera una práctica recomendada detectar solo los errores que le interesan. En el caso de shutil.rmtreeque sea probable OSError:

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

Si quiere ignorar silenciosamente ese error, haría:

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

¿Por qué? Digamos que (de alguna manera) accidentalmente pasa la función a un entero en lugar de una cadena, como:

shutil.rmtree(2)

Aparecerá el error "TypeError: coaccionar a Unicode: necesita cadena o buffer, int encontrado" - probablemente no quiera ignorar eso, lo que puede ser difícil de depurar.

Si definitivamente desea ignorar todos los errores, capture en Exceptionlugar de una except:declaración simple . De nuevo por qué?

Al no especificar una excepción, se detectan todas las excepciones, incluida la SystemExitexcepción que, por ejemplo, sys.exit()utiliza:

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

Compare esto con lo siguiente, que sale correctamente:

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

Si desea escribir un código de comportamiento cada vez mejor, la OSErrorexcepción puede representar varios errores, pero en el ejemplo anterior solo queremos ignorar Errno 2, por lo que podríamos ser aún más específicos:

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
fuente
1
shutil.rmtreeno es el mejor ejemplo, porque solo lo ignore_errors=True
usarías
113

Cuando solo quieres hacer un intento de captura sin manejar la excepción, ¿cómo lo haces en Python?

Depende de lo que quieras decir con "manipulación".

Si quiere atraparlo sin realizar ninguna acción, el código que publicó funcionará.

Si quiere decir que desea tomar medidas sobre una excepción sin detener la subida de la excepción, entonces quiere algo como esto:

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

Primero cito la respuesta de Jack O'Connor de este hilo . El hilo de referencia se cerró, así que escribo aquí:

"Hay una nueva forma de hacer esto en Python 3.4:

from contextlib import suppress

with suppress(Exception):
    # your code

Aquí está el commit que lo agregó: http://hg.python.org/cpython/rev/406b47c64480

Y aquí está el autor, Raymond Hettinger, hablando sobre esto y todo tipo de otras características de Python: https://youtu.be/OSGv2VnC0go?t=43m23s

Mi adición a esto es el equivalente a Python 2.7:

from contextlib import contextmanager

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

Luego lo usas como en Python 3.4:

with ignored(Exception):
    # your code
Jabba
fuente
55

Por completitud:

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

También tenga en cuenta que puede capturar la excepción de esta manera:

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

... y vuelve a plantear la excepción así:

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

... ejemplos del tutorial de Python .

cbare
fuente
43

¿Cómo ignorar adecuadamente las excepciones?

Hay varias maneras de hacer esto.

Sin embargo, la elección del ejemplo tiene una solución simple que no cubre el caso general.

Específico para el ejemplo:

En vez de

try:
    shutil.rmtree(path)
except:
    pass

Hacer esto:

shutil.rmtree(path, ignore_errors=True)

Este es un argumento específico para shutil.rmtree. Puede ver la ayuda al hacer lo siguiente, y verá que también puede permitir la funcionalidad en los errores.

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

Como esto solo cubre el caso estrecho del ejemplo, demostraré aún más cómo manejar esto si esos argumentos de palabras clave no existieran.

Enfoque general

Dado que lo anterior solo cubre el caso estrecho del ejemplo, demostraré aún más cómo manejar esto si esos argumentos de palabras clave no existieran.

Nuevo en Python 3.4:

Puede importar el suppressadministrador de contexto:

from contextlib import suppress

Pero solo suprima la excepción más específica:

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

Ignorarás silenciosamente un FileNotFoundError:

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

De los documentos :

Al igual que con cualquier otro mecanismo que suprima completamente las excepciones, este administrador de contexto debe usarse solo para cubrir errores muy específicos en los que se sabe que continuar silenciosamente con la ejecución del programa es lo correcto.

Tenga en cuenta que suppressy FileNotFoundErrorsolo están disponibles en Python 3.

Si desea que su código también funcione en Python 2, consulte la siguiente sección:

Python 2 y 3:

Cuando solo quieres probar / excepto sin manejar la excepción, ¿cómo lo haces en Python?

¿Es la siguiente la forma correcta de hacerlo?

try :
    shutil.rmtree ( path )
except :
    pass

Para el código compatible con Python 2, passes la forma correcta de tener una declaración que no sea operativa. Pero cuando se hace una desnuda except:, eso es lo mismo que hacer except BaseException:que incluye GeneratorExit, KeyboardInterrupty SystemExit, y, en general, que no quieren coger esas cosas.

De hecho, debe ser tan específico al nombrar la excepción como sea posible.

Aquí hay parte de la jerarquía de excepciones de Python (2) y, como puede ver, si detecta Excepciones más generales, puede ocultar problemas que no esperaba:

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

Probablemente desee capturar un OSError aquí, y tal vez la excepción que no le importa es si no hay un directorio.

Podemos obtener ese número de error específico de la errnobiblioteca y volver a subirlo si no tenemos eso:

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 

Tenga en cuenta que un aumento simple genera la excepción original, que probablemente es lo que desea en este caso. Escrito de manera más concisa, ya que realmente no necesitamos explícitamente passcon el código en el manejo de excepciones:

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

Cuando solo quieres hacer un intento de captura sin manejar la excepción, ¿cómo lo haces en Python?

Esto lo ayudará a imprimir cuál es la excepción :( es decir, intente capturar sin manejar la excepción e imprima la excepción).

import sys
try:
    doSomething()
except:
    print "Unexpected error:", sys.exc_info()[0]
Irengbam Tilokchan Singh
fuente
10
try:
      doSomething()
except Exception: 
    pass
else:
      stuffDoneIf()
      TryClauseSucceeds()

Para su información, la cláusula else puede ir después de todas las excepciones y solo se ejecutará si el código en el intento no causa una excepción.

MrChrisRodriguez
fuente
1
Finalmente una buena explicación de elseen este contexto. Y añadir que finallyserá siempre correr detrás de cualquiera (o no es una excepción).
not2qubit
5

Necesitaba ignorar los errores en múltiples comandos y eso fue lo que hice.

import fuckit

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

helper()
hombre de la ciudad
fuente
+1 porque definitivamente me
alegraste el
3

En Python, manejamos excepciones similares a otro lenguaje, pero la diferencia es alguna diferencia de sintaxis, por ejemplo,

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 'CLASIFICADO'
fuente
-4

Usualmente solo hago:

try:
    doSomething()
except:
    _ = ""
Dylan Strudwick
fuente
3
Te sugiero que reemplaces _ = ""con pass.
Legorooj