Buscar..


Introducción

Los errores detectados durante la ejecución se denominan excepciones y no son incondicionalmente fatales. La mayoría de las excepciones no son manejadas por los programas; es posible escribir programas que manejen excepciones seleccionadas. Hay características específicas en Python para lidiar con las excepciones y la lógica de excepciones. Además, las excepciones tienen una jerarquía de tipos enriquecidos, todos heredados del tipo BaseException .

Sintaxis

  • levantar excepción
  • elevar # re-elevar una excepción que ya ha sido planteada
  • generar excepción de causa # Python 3 - establecer causa de excepción
  • generar excepción desde Ninguna # Python 3 - suprimir todo el contexto de excepción
  • tratar:
  • excepto [tipos de excepción] [ como identificador ] :
  • más:
  • finalmente:

Levantando excepciones

Si su código encuentra una condición que no sabe cómo manejar, como un parámetro incorrecto, debe generar la excepción apropiada.

def even_the_odds(odds):
    if odds % 2 != 1:
        raise ValueError("Did not get an odd number")
    
    return odds + 1

Atrapar excepciones

Utilice try...except: para detectar excepciones. Debe especificar una excepción tan precisa como pueda:

try:
    x = 5 / 0
except ZeroDivisionError as e:
    # `e` is the exception object
    print("Got a divide by zero! The exception was:", e)
    # handle exceptional case
    x = 0  
finally:
    print "The END"
    # it runs no matter what execute.

La clase de excepción que se especifica, en este caso, ZeroDivisionError , captura cualquier excepción que sea de esa clase o de cualquier subclase de esa excepción.

Por ejemplo, ZeroDivisionError es una subclase de ArithmeticError :

>>> ZeroDivisionError.__bases__
(<class 'ArithmeticError'>,)

Y así, lo siguiente seguirá ZeroDivisionError :

try:
    5 / 0
except ArithmeticError:
    print("Got arithmetic error")

Ejecutando código de limpieza con finalmente

A veces, es posible que desee que ocurra algo, independientemente de la excepción que haya ocurrido, por ejemplo, si tiene que limpiar algunos recursos.

El bloque finally de una cláusula de try ocurrirá independientemente de si se produjeron excepciones.

resource = allocate_some_expensive_resource()
try:
    do_stuff(resource)
except SomeException as e:
    log_error(e)
    raise  # re-raise the error
finally:
    free_expensive_resource(resource)

Este patrón a menudo se maneja mejor con los administradores de contexto (usando la declaración with ).

Re-elevando excepciones

A veces desea capturar una excepción solo para inspeccionarla, por ejemplo, para fines de registro. Después de la inspección, desea que la excepción continúe propagándose como lo hizo antes.

En este caso, simplemente use la instrucción raise sin parámetros.

try:
    5 / 0
except ZeroDivisionError:
    print("Got an error")
    raise

Sin embargo, tenga en cuenta que alguien que se encuentre más arriba en la pila de personas que llaman todavía puede detectar la excepción y manejarla de alguna manera. La salida realizada podría ser una molestia en este caso porque ocurrirá en cualquier caso (capturado o no capturado). Por lo tanto, podría ser una mejor idea plantear una excepción diferente, que contenga su comentario sobre la situación, así como la excepción original:

try:
    5 / 0
except ZeroDivisionError as e:
    raise ZeroDivisionError("Got an error", e)

Pero esto tiene el inconveniente de reducir la traza de excepción exactamente a este raise mientras que la raise sin argumento conserva la traza de excepción original.

En Python 3 puedes mantener la pila original usando la sintaxis de raise - from :

    raise ZeroDivisionError("Got an error") from e

Cadena de excepciones con aumento de

En el proceso de manejar una excepción, es posible que desee plantear otra excepción. Por ejemplo, si obtiene un IOError mientras lee un archivo, es posible que desee plantear un error específico de la aplicación para que se presente a los usuarios de su biblioteca.

Python 3.x 3.0

Puede encadenar excepciones para mostrar cómo procedió el manejo de las excepciones:

>>> try:
    5 / 0
except ZeroDivisionError as e:
    raise ValueError("Division failed") from e

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
ValueError: Division failed

Jerarquía de excepciones

El manejo de excepciones se produce en función de una jerarquía de excepciones, determinada por la estructura de herencia de las clases de excepciones.

Por ejemplo, IOError y OSError son subclases de EnvironmentError . El código que captura un IOError no detectará un OSError . Sin embargo, el código que atrapa un EnvironmentError detectará tanto IOError s como OSError s.

La jerarquía de las excepciones incorporadas:

Python 2.x 2.3
BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StandardError
      |    +-- BufferError
      |    +-- ArithmeticError
      |    |    +-- FloatingPointError
      |    |    +-- OverflowError
      |    |    +-- ZeroDivisionError
      |    +-- AssertionError
      |    +-- AttributeError
      |    +-- EnvironmentError
      |    |    +-- IOError
      |    |    +-- OSError
      |    |         +-- WindowsError (Windows)
      |    |         +-- VMSError (VMS)
      |    +-- EOFError
      |    +-- ImportError
      |    +-- LookupError
      |    |    +-- IndexError
      |    |    +-- KeyError
      |    +-- MemoryError
      |    +-- NameError
      |    |    +-- UnboundLocalError
      |    +-- ReferenceError
      |    +-- RuntimeError
      |    |    +-- NotImplementedError
      |    +-- SyntaxError
      |    |    +-- IndentationError
      |    |         +-- TabError
      |    +-- SystemError
      |    +-- TypeError
      |    +-- ValueError
      |         +-- UnicodeError
      |              +-- UnicodeDecodeError
      |              +-- UnicodeEncodeError
      |              +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
       +-- ImportWarning
       +-- UnicodeWarning
       +-- BytesWarning
Python 3.x 3.0
BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

Las excepciones son objetos también

Las excepciones son solo objetos de Python normales que heredan de la BaseException . Una secuencia de comandos de Python puede usar la instrucción raise para interrumpir la ejecución, lo que hace que Python imprima un seguimiento de pila de la pila de llamadas en ese punto y una representación de la instancia de excepción. Por ejemplo:

>>> def failing_function():
...     raise ValueError('Example error!')
>>> failing_function()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in failing_function
ValueError: Example error!

que dice que un ValueError con el mensaje 'Example error!' fue planteado por nuestro failing_function() , que fue ejecutado en el intérprete.

El código de llamada puede elegir manejar cualquier excepción de todo tipo que una llamada pueda generar:

>>> try:
...     failing_function()
... except ValueError:
...     print('Handled the error')
Handled the error

Puede obtener los objetos de excepción asignándolos en la parte except... del código de manejo de excepciones:

>>> try:
...     failing_function()
... except ValueError as e:
...     print('Caught exception', repr(e))
Caught exception ValueError('Example error!',)

Puede encontrar una lista completa de las excepciones de Python incorporadas junto con sus descripciones en la Documentación de Python: https://docs.python.org/3.5/library/exceptions.html . Y aquí está la lista completa organizada jerárquicamente: Jerarquía de excepciones .

Creación de tipos de excepción personalizados

Crea una clase heredada de Exception :

class FooException(Exception):
    pass
try:
    raise FooException("insert description here")
except FooException:
    print("A FooException was raised.")

u otro tipo de excepción:

class NegativeError(ValueError):
      pass

def foo(x):
    # function that only accepts positive values of x
    if x < 0:
        raise NegativeError("Cannot process negative numbers")
    ...  # rest of function body
try:
    result = foo(int(input("Enter a positive integer: ")))  # raw_input in Python 2.x
except NegativeError:
    print("You entered a negative number!")
else:
    print("The result was " + str(result))

No atrapes todo!

Aunque a menudo es tentador atrapar todas las Exception :

try:
    very_difficult_function()
except Exception:
    # log / try to reconnect / exit gratiously
finally:
    print "The END"
    # it runs no matter what execute.

O incluso todo (que incluye BaseException y todos sus hijos, incluida la Exception ):

try:
    even_more_difficult_function()
except:
    pass  # do whatever needed

En la mayoría de los casos es una mala práctica. Es posible que SystemExit más de lo previsto, como SystemExit , KeyboardInterrupt y MemoryError , cada uno de los cuales generalmente debe manejarse de manera diferente a los errores habituales del sistema o la lógica. También significa que no hay una comprensión clara de qué puede hacer mal el código interno y cómo recuperarse adecuadamente de esa condición. Si está detectando cada error, no sabrá qué error ocurrió o cómo solucionarlo.

Esto se conoce más comúnmente como "enmascaramiento de errores" y debe evitarse. Deje que su programa se bloquee en lugar de fallar silenciosamente o incluso peor, fallando en un nivel más profundo de ejecución. (Imagina que es un sistema transaccional)

Por lo general, estas construcciones se usan en el nivel más externo del programa, y ​​registrarán los detalles del error para que el error se pueda corregir, o el error se pueda manejar más específicamente.

Atrapando múltiples excepciones

Hay algunas maneras de atrapar múltiples excepciones .

La primera es creando una tupla de los tipos de excepción que desea capturar y manejar de la misma manera. Este ejemplo hará que el código ignore las excepciones KeyError y AttributeError .

try:
    d = {}
    a = d[1]
    b = d.non_existing_field
except (KeyError, AttributeError) as e:
    print("A KeyError or an AttributeError exception has been caught.")

Si desea manejar diferentes excepciones de diferentes maneras, puede proporcionar un bloque de excepción separado para cada tipo. En este ejemplo, todavía KeyError y AttributeError , pero manejamos las excepciones de diferentes maneras.

try:
    d = {}
    a = d[1]
    b = d.non_existing_field
except KeyError as e:
    print("A KeyError has occurred. Exception message:", e)
except AttributeError as e:
    print("An AttributeError has occurred. Exception message:", e)

Ejemplos prácticos de manejo de excepciones.

Entrada del usuario

Imagina que quieres que un usuario ingrese un número a través de una input . Desea asegurarse de que la entrada es un número. Puedes usar try / except de esto:

Python 3.x 3.0
while True:
    try:
        nb = int(input('Enter a number: '))
        break
    except ValueError:
        print('This is not a number, try again.')

Nota: Python 2.x usaría raw_input en raw_input lugar; la input la función existe en Python 2.x pero tiene una semántica diferente. En el ejemplo anterior, la input también aceptaría expresiones como 2 + 2 que se evalúan como un número.

Si la entrada no se pudo convertir en un entero, se ValueError un ValueError . Puedes atraparlo con except . Si se plantea no es una excepción, break salta fuera del bucle. Después del bucle, nb contiene un entero.

Los diccionarios

Imagine que está iterando sobre una lista de enteros consecutivos, como el range(n) , y tiene una lista de diccionarios d que contiene información sobre cosas que hacer cuando encuentra algunos enteros en particular, por ejemplo, omita los d[i] siguientes .

d = [{7: 3}, {25: 9}, {38: 5}]

for i in range(len(d)):
    do_stuff(i)
    try:
       dic = d[i]
       i += dic[i]
    except KeyError:
       i += 1

Se KeyError un KeyError cuando intente obtener un valor de un diccionario para una clave que no existe.

Más

El código en un bloque else solo se ejecutará si el código en el bloque try no genera excepciones. Esto es útil si tiene algún código que no desea ejecutar si se lanza una excepción, pero no quiere que se detecten excepciones lanzadas por ese código.

Por ejemplo:

try:
    data = {1: 'one', 2: 'two'}
    print(data[1])
except KeyError as e:
    print('key not found')
else:
    raise ValueError()
# Output: one
# Output: ValueError

Tenga en cuenta que este tipo de else: no se puede combinar con if inicia la cláusula else en un elif . Si usted tiene un siguiente if que necesita para mantenerse con sangría debajo de esa else: :

try:
    ...
except ...:
    ...
else:
    if ...:
        ...
    elif ...:
        ...
    else:
        ...


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow