try - Levantando(lanzando) manualmente una excepción en Python




try catch python print exception (4)

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


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

Utilice el constructor de excepciones más específico que se adapta 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 elevar una excepción genérica. Para atraparlo, deberás capturar todas las demás excepciones más específicas que la subclase.

Problema 1: Ocultando 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 las 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

Buenas Prácticas: raise declaración

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

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

lo que también permite fácilmente pasar 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 atributo args en el objeto Exception. 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, se agregó un atributo de message real a BaseException a favor de alentar a los usuarios a que hagan excepciones en la subclase y dejen de usar args , pero la introducción del message y la desestimación original de args se han retraído .

Buenas prácticas: except cláusula

Cuando se encuentra 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 aumentar. La mejor manera de hacer esto mientras se conserva el seguimiento de la pila es usar una declaración de aumento desnudo. 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 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 , prefiero usar una raise simple para volver a subir.

Para explicar: el 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 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, por ejemplo, establecer 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 esta no es una buena práctica y que la sintaxis no es válida en Python 3 (lo que hace que 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: evita manipular manualmente las trazas. Es menos eficiente y más propenso a errores. Y si está usando subprocesos y sys.exc_info , puede incluso obtener el sys.exc_info incorrecto (especialmente si está utilizando el manejo de excepciones para el flujo de control, lo que personalmente tiendo a evitar).

Python 3, encadenamiento de excepciones

En Python 3, puede encadenar excepciones, que conservan las trazas de retorno:

    raise RuntimeError('specific message') from error

Estar atentos

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

Métodos en desuso:

Estos pueden ocultar fácilmente e incluso entrar en el código de producción. Desea generar una excepción, y hacerlas generará una excepción, ¡ pero no la prevista!

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

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

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

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

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

Ejemplo de uso

Aumento de excepciones para advertir a los consumidores de mi API si la usan de forma incorrecta:

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

Crea tus propios tipos de error cuando te convenga.

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

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

NO HAGAS ESTO . Elevar una Exception desnuda no es absolutamente lo correcto; ver share lugar.

No se puede obtener mucho más pitón que esto:

raise Exception("I know python!")

Consulte los documentos de declaración de subida para python si desea obtener más información.


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

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

Tenga en cuenta que puede generar 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á "programa salido" a stderr antes de cerrar el programa.







exception-handling