Levantando manualmente (lanzando) una excepción en Python

¿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 adapte 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 "", line 1, in  File "", line 3, in demo_no_catch Exception: general exceptions not caught by specific handling 

Buenas Prácticas: raise statement

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 .

Mejores 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 boost. La mejor manera de hacer esto mientras se preserva el seguimiento de la stack es usar una statement 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 stack (y el valor de error) con sys.exc_info() , pero esto es 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 syntax 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] + ' ',) 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 syntax 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 "", line 1, in  File "", line 3, in catch_error_modify_message File "", line 2, in error ValueError: oops!  

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 ocultarse 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 en realidad generará un TypeError, porque 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, en absoluto, lo correcto; ver la excelente respuesta de Aaron Hall en su lugar.

No se puede obtener mucho más python que esto:

 raise Exception("I know python!") 

Consulte los documentos de statement 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) 

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

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

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

Si usa la raise exception (args) para generar una excepción, los args se imprimirán 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. risa

raise statement sin ningún argumento re-plantea la última excepción. Esto es útil si necesita realizar algunas acciones después de capturar la excepción y luego desea volver a elevarla. Pero si no hubo una excepción antes, la statement de raise genera una excepción de TypeError .

 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  #ZeroDivisionError: division by zero 

4. generar excepción (args) de original_exception

Esta statement se utiliza para crear un encadenamiento de excepciones en el que una excepción que se produce 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 

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 progtwig pero es posible que desee saber qué sucedió. Así que puede usar esto.

 raise SystemExit("program exited") 

esto imprimirá “progtwig salido” a stderr antes de cerrar el progtwig.

Otra forma de lanzar una excepción es assert . Puede usar aseverar para verificar que se cumple una condición; de lo contrario, generará AssertionError . Para más detalles echa un vistazo aquí .

 def avg(marks): assert len(marks) != 0,"List is empty." return sum(marks)/len(marks) mark2 = [55,88,78,90,79] print("Average of mark2:",avg(mark2)) mark1 = [] print("Average of mark1:",avg(mark1)) 

Solo para tener en cuenta: hay ocasiones en las que QUIERES manejar excepciones genéricas. Si está procesando un montón de archivos y está registrando sus errores, es posible que desee detectar cualquier error que ocurra en un archivo, registrarlo y continuar procesando el rest de los archivos. En ese caso, un try except Exception: bloquea una buena manera de hacerlo. Aún así, querrá raise excepciones específicas para que sepa lo que significan.