Pregunta Manualmente levantando (lanzando) una excepción en Python


¿Cómo puedo generar una excepción en Python para que luego pueda atraparse a través de un except ¿bloquear?


1516
2018-01-12 21:07


origen


Respuestas:


¿Cómo lanzo / lanzo una excepción manualmente 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 levante excepciones genéricas

Evite generar una Excepción genérica. Para atraparlo, tendrás que atrapar 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 atrapará

y capturas más específicas no captará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: raise declaración

En su lugar, use el constructor Excepción más específico que se ajuste semánticamente a su problema.

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

que también permite que se pase una cantidad arbitraria de argumentos al constructor:

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

Estos argumentos son accedidos por args atributo en el objeto de excepción. 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, un real message atributo fue agregado a BaseException a favor de alentar a los usuarios a subclasificar Excepciones y dejar de usar args, pero la introducción de message y la desaprobación original de args ha sido retractada.

Mejores prácticas: except cláusula

Cuando está dentro de una cláusula except, es posible que desee, por ejemplo, registrar que ocurrió un tipo específico de error, y luego volver a subir. La mejor manera de hacerlo mientras se conserva el seguimiento de la pila es usar 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 modifique sus errores ... pero si insiste.

Puede conservar el stacktrace (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, prefiere usar un desnudo raise para volver a subir.

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

type, value, traceback = sys.exc_info()

Esta es la sintaxis en Python 2: tenga en cuenta que esto 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 desea, puede modificar lo que sucede con su nuevo aumento, p. Ej. estableciendo nuevos argumentos para 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 esto es no es una buena práctica y es sintaxis inválida en Python 3 (lo que hace que mantener la compatibilidad sea mucho más difícil de solucionar).

>>> 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])

De nuevo: evite la manipulación manual de los registros de seguimiento. Sus menos eficiente y más propenso a errores Y si estás usando enhebrar y sys.exc_info es posible que incluso obtenga el rastreo incorrecto (especialmente si está utilizando el manejo de excepciones para el flujo de control, que yo personalmente tendería a evitar).

Python 3, cadena de excepciones

En Python 3, puede encadenar excepciones, que conservan los registros de seguimiento:

    raise RuntimeError('specific message') from error

Tenga en cuenta:

  • esta hace permitir cambiar el tipo de error planteado, y
  • esto es no compatible con Python 2.

Métodos obsoletos:

Estos pueden esconderse fácilmente e incluso entrar en el código de producción. Desea plantear una excepción, y hacerlas generará una excepción, pero no el previsto!

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

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

Solamente válido en versiones mucho más antiguas de Python (2.4 y menos), aún puede ver personas que están creando cadenas:

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

En todas las versiones modernas, esto generará un TypeError, porque no está subiendo un tipo BaseException. Si no está buscando la excepción correcta y no tiene un revisor consciente del problema, podría entrar en producción.

Ejemplo de uso

Subo Excepciones para advertir a los consumidores de 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 a propósito

"Quiero cometer un error a propósito, por lo que entraría en el excepto"

Puede crear sus propios tipos de error, si desea indicar que algo específico está mal con su aplicación, simplemente subclass 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.')

1890
2018-06-05 16:30



NO HAGAS ESTO. Levantando un desnudo Exception es absolutamente no lo correcto a hacer; ver La excelente respuesta de Aaron Hall en lugar.

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

raise Exception("I know python!")

Ver los documentos de declaración de aumento para python si quieres más información.


541
2018-01-12 21:08



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

if 0 < distance <= RADIUS:
    #Do something.
elif RADIUS < distance:
    #Do something.
else:
    raise AssertionError("Unexpected value of 'distance'!", distance)

29
2018-05-19 04:55



En Python3 hay 4 sintaxis diferentes para las excepciones de rasing:

1. raise exception 
2. raise exception (args) 
3. raise
4. raise exception (args) from original_exception

1. elevar excepción vs. 2. elevar excepción (args)

Si utiliza raise exception (args)  para levantar una excepción, entonces el args se imprimirá 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 execption 
    try:
        raise ValueError
    except ValueError as exp:
        print ("Error", exp)     # Output -> Error 

3.raise

raise declaración sin ningún argumento vuelve a levantar la última excepción. Esto es útil si necesita realizar algunas acciones después de atrapar la excepción y luego desea volver a plantearla. Pero si no hubo ninguna excepción antes, raise declaración plantea TypeError Excepció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 8, in <module>
                             #ZeroDivisionError: division by zero

4. elevar la excepción (args) desde la excepción original

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__)

Salida:

ZeroDivisionError --  division by zero
MyException Zero Division 
division by zero

22
2017-11-08 17:54



Lea primero las respuestas existentes, esto es solo un apéndice.

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

Ejemplo:

raise SystemExit

sale del programa, pero es posible que desee saber qué sucedió. Así que puede usar esto.

raise SystemExit("program exited")

esto imprimirá "program exit" en stderr antes de cerrar el programa.


5
2018-03-29 11:59