Generar (lanzar) manualmente una excepción en Python

Resuelto TIMEX asked hace 14 años • 11 respuestas

¿Cómo puedo generar una excepción en Python para que luego pueda detectarse mediante un exceptbloque?

TIMEX avatar Jan 13 '10 04:01 TIMEX
Aceptado

¿Cómo lanzo/provoco manualmente una excepción en Python?

Utilice el constructor de excepciones más específico que se ajuste semánticamente a su problema .

Sea específico en su mensaje, por ejemplo:

raise ValueError('A very specific bad thing happened.')

No plantee excepciones genéricas

Evite plantear un genérico Exception. Para detectarlo, tendrá que detectar todas las demás excepciones más específicas que lo subclasifican.

Problema 1: ocultar errores

raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.

Por ejemplo:

def demo_bad_catch():
    try:
        raise ValueError('Represents a hidden bug, do not catch this')
        raise Exception('This is the exception you expect to handle')
    except Exception as error:
        print('Caught this error: ' + repr(error))

>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)

Problema 2: no capta

Y capturas más específicas no detectarán la excepción general:

def demo_no_catch():
    try:
        raise Exception('general exceptions not caught by specific handling')
    except ValueError as e:
        print('we will not catch exception: Exception')
 

>>> demo_no_catch()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling

Mejores prácticas: raisedeclaración

En su lugar, utilice el constructor de excepciones más específico que se ajuste semánticamente a su problema .

raise ValueError('A very specific bad thing happened')

que también permite pasar cómodamente un número arbitrario de argumentos al constructor:

raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz') 

A estos argumentos se accede mediante el argsatributo del Exceptionobjeto. Por ejemplo:

try:
    some_code_that_may_raise_our_value_error()
except ValueError as err:
    print(err.args)

huellas dactilares

('message', 'foo', 'bar', 'baz')    

En Python 2.5, messagese agregó un atributo real BaseExceptiona favor de alentar a los usuarios a crear subclases de excepciones y dejar de usar args, pero se retiró la introducciónmessage y la desaprobación original de args .

Mejores Prácticas: exceptcláusula

Cuando esté dentro de una cláusula de excepción, es posible que desee, por ejemplo, registrar que ocurrió un tipo específico de error y luego volver a generarlo. La mejor manera de hacer esto preservando el seguimiento de la pila es utilizar una declaración de aumento simple. Por ejemplo:

logger = logging.getLogger(__name__)

try:
    do_something_in_app_that_breaks_easily()
except AppError as error:
    logger.error(error)
    raise                 # just this!
    # raise AppError      # Don't do this, you'll lose the stack trace!

No modifiques tus errores... pero si insistes.

Puede conservar el seguimiento de la pila (y el valor de error) con sys.exc_info(), pero esto es mucho más propenso a errores y tiene problemas de compatibilidad entre Python 2 y 3 ; prefiera usar un bare raisepara volver a generar.

Para explicar: sys.exc_info()devuelve el tipo, el valor y el rastreo.

type, value, traceback = sys.exc_info()

Esta es la sintaxis en Python 2; tenga en cuenta que no es compatible con Python 3:

raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]

Si lo deseas, puedes modificar lo que sucede con tu nuevo aumento, por ejemplo, estableciendo un nuevo argspara la instancia:

def error():
    raise ValueError('oops!')

def catch_error_modify_message():
    try:
        error()
    except ValueError:
        error_type, error_instance, traceback = sys.exc_info()
        error_instance.args = (error_instance.args[0] + ' <modification>',)
        raise error_type, error_instance, traceback

Y hemos conservado todo el rastreo mientras modificamos los argumentos. Tenga en cuenta que esta no es una práctica recomendada y su sintaxis no es válida en Python 3 (lo que hace que sea mucho más difícil mantener la compatibilidad).

>>> catch_error_modify_message()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in catch_error_modify_message
  File "<stdin>", line 2, in error
ValueError: oops! <modification>

En Python 3 :

raise error.with_traceback(sys.exc_info()[2])

Nuevamente: evite manipular manualmente los rastreos. Es menos eficiente y más propenso a errores. Y si está utilizando subprocesos e sys.exc_infoincluso puede obtener un rastreo incorrecto (especialmente si está utilizando el manejo de excepciones para el flujo de control, lo cual personalmente tendería a evitar).

Python 3, encadenamiento de excepciones

En Python 3, puedes encadenar excepciones, que preservan los rastreos:

raise RuntimeError('specific message') from error

Tenga en cuenta:

  • esto permite cambiar el tipo de error generado, y
  • esto no es compatible con Python 2.

Métodos obsoletos:

Estos pueden ocultarse fácilmente e incluso ingresar al código de producción. Quiere generar una excepción y, al hacerlo, se generará una excepción, ¡ pero no la prevista!

Válido en Python 2, pero no en Python 3 es lo siguiente:

raise ValueError, 'message' # Don't do this, it's deprecated!

Solo es válido en versiones mucho más antiguas de Python (2.4 y anteriores), es posible que aún veas personas levantando cadenas:

raise 'message' # really really wrong. don't do this.

En todas las versiones modernas, esto en realidad generará un TypeError, porque no estás generando un BaseExceptiontipo. Si no está verificando la excepción correcta y no tiene un revisor que esté al tanto del problema, podría entrar en producción.

Uso de ejemplo

Planteo Excepciones para advertir a los consumidores sobre mi API si la están usando incorrectamente:

def api_func(foo):
    '''foo should be either 'baz' or 'bar'. returns something very useful.'''
    if foo not in _ALLOWED_ARGS:
        raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))

Cree sus propios tipos de error cuando sea necesario

"Quiero cometer un error a propósito, para que entre en excepción"

Puede crear sus propios tipos de error, si desea indicar que algo específico está mal con su aplicación, simplemente subclase el punto apropiado en la jerarquía de excepciones:

class MyAppLookupError(LookupError):
    '''raise this when there's a lookup error for my app'''

y uso:

if important_key not in resource_dict and not ok_to_be_missing:
    raise MyAppLookupError('resource is missing, and that is not ok.')
Russia Must Remove Putin avatar Jun 05 '2014 16:06 Russia Must Remove Putin

No hagas esto . Criar un desnudo noException es en absolutolo correcto;consulte la excelente respuesta de Aaron Hall .

No puede ser mucho más pitónico que esto:

raise Exception("I know Python!")

Reemplace Exceptioncon el tipo específico de excepción que desea generar.

Consulte la documentación de la declaración de aumento para Python si desea obtener más información.

Gabriel Hurley avatar Jan 12 '2010 21:01 Gabriel Hurley

En Python 3 hay cuatro sintaxis diferentes para generar excepciones:

  1. levantar excepción
  2. generar excepción (argumentos)
  3. aumentar
  4. generar excepción (argumentos) de original_exception

1. Generar excepción versus 2. generar excepción (argumentos)

Si utiliza raise exception (args)para generar una excepción, se argsimprimirá cuando imprima el objeto de excepción, como se muestra en el siguiente ejemplo.

# Raise exception (args)
try:
    raise ValueError("I have raised an Exception")
except ValueError as exp:
    print("Error", exp)     # Output -> Error I have raised an Exception


# Raise exception
try:
    raise ValueError
except ValueError as exp:
    print("Error", exp)     # Output -> Error

3. Aumento de declaración

La raiseafirmación sin ningún argumento vuelve a plantear la última excepción.

Esto es útil si necesita realizar algunas acciones después de detectar la excepción y luego desea volver a generarla. Pero si no hubo ninguna excepción antes, la raisedeclaración genera una TypeErrorExcepción.

def somefunction():
    print("some cleaning")

a = 10
b = 0
result = None

try:
    result = a / b
    print(result)

except Exception:            # Output ->
    somefunction()           # Some cleaning
    raise                    # Traceback (most recent call last):
                             # File "python", line 9, in <module>
                             # ZeroDivisionError: division by zero

4. Generar excepción (argumentos) de original_exception

Esta declaración se utiliza para crear un encadenamiento de excepciones en el que una excepción que se genera en respuesta a otra excepción puede contener los detalles de la excepción original, como se muestra en el siguiente ejemplo.

class MyCustomException(Exception):
    pass

a = 10
b = 0
reuslt = None
try:
    try:
        result = a / b

    except ZeroDivisionError as exp:
        print("ZeroDivisionError -- ",exp)
        raise MyCustomException("Zero Division ") from exp

except MyCustomException as exp:
    print("MyException",exp)
    print(exp.__cause__)

Producción:

ZeroDivisionError --  division by zero
MyException Zero Division
division by zero
N Randhawa avatar Nov 08 '2016 17:11 N Randhawa

Para el caso común en el que necesita lanzar una excepción en respuesta a algunas condiciones inesperadas, y que nunca tiene la intención de detectar, sino simplemente fallar rápidamente para permitirle depurar desde allí si alguna vez sucede, la más lógica parece ser AssertionError:

if 0 < distance <= RADIUS:
    #Do something.
elif RADIUS < distance:
    #Do something.
else:
    raise AssertionError("Unexpected value of 'distance'!", distance)
Evgeni Sergeev avatar May 19 '2015 04:05 Evgeni Sergeev

Lea primero las respuestas existentes, esto es solo una adición.

Tenga en cuenta que puede generar excepciones con o sin argumentos.

Ejemplo:

raise SystemExit

sale del programa, pero es posible que desees saber qué pasó. Entonces puedes usar esto.

raise SystemExit("program exited")

Esto imprimirá "programa salido" como error estándar antes de cerrar el programa.

Anant Prakash avatar Mar 29 '2017 11:03 Anant Prakash