validar try tipos sirve que por pass para excepciones error ejemplos diferentes archivos anidados python logging exception-handling flow-control try-finally

python - try - ¿Cómo determinar si se generó una excepción una vez que estás en el bloque finally?



try except anidados python (5)

Usando un gestor de contexto

Puede usar un gestor de contexto personalizado, por ejemplo:

class DidWeRaise: __slots__ = (''exception_happened'', ) # instances will take less memory def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): # If no exception happened the `exc_type` is None self.exception_happened = exc_type is not None

Y luego usa eso dentro del try :

try: with DidWeRaise() as error_state: # funky code finally: if error_state.exception_happened: print(''the funky code raised'')

Sigue siendo una variable adicional, pero probablemente sea mucho más fácil de reutilizar si desea usarlo en varios lugares. Y no necesita alternarlo usted mismo.

Usando una variable

En caso de que no desee el gestor de contexto, invertiría la lógica del desencadenador y lo cambiaría solo en caso de que no haya ocurrido ninguna excepción. De esta forma, no necesita un caso except para excepciones que no desea manejar. El lugar más apropiado sería la cláusula else que se ingresa en caso de que el try no arrojara una excepción:

exception_happened = True try: # funky code except HandleThis: # handle this kind of exception else: exception_happened = False finally: if exception_happened: print(''the funky code raised'')

Y como ya se señaló en lugar de tener una variable "alternar", podría reemplazarla (en este caso) con la función de registro deseada:

mylog = mylogger.WARNING try: with LogCapture() as log: funky_code() except HandleThis: # handle this kind of exception else: # In case absolutely no exception was thrown in the try we can log on debug level mylog = mylogger.DEBUG finally: for record in log.captured: mylog(record.msg, record.args)

Por supuesto, también funcionaría si lo colocas al final de tu try (como sugieren otras respuestas aquí), pero prefiero la cláusula else porque tiene más significado ("ese código debe ejecutarse solo si no hubo excepción en el bloque try ") y puede ser más fácil de mantener a largo plazo. Aunque todavía es más necesario mantener que el administrador de contexto porque la variable se establece y se alterna en diferentes lugares.

Uso de sys.exc_info (funciona solo para excepciones no controladas)

El último enfoque que quiero mencionar probablemente no sea útil para usted, pero tal vez sea útil para futuros lectores que solo quieran saber si hay una excepción no controlada (una excepción que no se detectó en ningún bloque except o se ha generado dentro de un bloque except ). En ese caso, puede usar sys.exc_info :

import sys try: # funky code except HandleThis: pass finally: if sys.exc_info()[0] is not None: # only entered if there''s an *unhandled* exception, e.g. NOT a HandleThis exception print(''funky code raised'')

¿Es posible decir si hubo una excepción una vez que está en la cláusula finally ? Algo como:

try: funky code finally: if ???: print(''the funky code raised'')

Estoy buscando hacer algo como esto más SECO:

try: funky code except HandleThis: # handle it raised = True except DontHandleThis: raised = True raise else: raised = False finally: logger.info(''funky code raised %s'', raised)

No me gusta que requiera capturar una excepción, que no tiene la intención de manejar, solo para establecer una bandera.

Como algunos comments piden menos "M" en el MCVE, aquí hay más antecedentes sobre el caso de uso. El problema real es acerca de la escalada de niveles de registro.

  • El código funky es de terceros y no se puede cambiar.
  • La excepción de falla y el seguimiento de la pila no contienen información de diagnóstico útil, por lo que usar logger.exception en un bloque except no es útil aquí.
  • Si se generó el código funky, entonces cierta información que necesito ver ya se ha registrado, en el nivel DEBUG. No podemos y no podemos manejar el error, pero queremos escalar el registro de DEPURACIÓN porque la información necesaria está ahí.
  • El código funky no aumenta, la mayoría de las veces. No quiero escalar los niveles de registro para el caso general, porque es demasiado detallado.

Por lo tanto, el código se ejecuta en un contexto de captura de registro (que configura los controladores personalizados para interceptar registros) y cierta información de depuración se vuelve a registrar retrospectivamente:

try: with LogCapture() as log: funky_code() # <-- third party badness finally: mylog = mylogger.WARNING if <there was exception> else mylogger.DEBUG for record in log.captured: mylog(record.msg, record.args)


Bien, entonces, ¿qué significa que realmente solo quieres modificar tu administrador de contexto existente o utilizar un enfoque similar? logbook realidad tiene algo llamado FingersCrossedHandler que haría exactamente lo que quieres. Pero podrías hacerlo tú mismo, como:

@contextmanager def LogCapture(): # your existing buffer code here level = logging.WARN try: yield except UselessException: level = logging.DEBUG raise # Or don''t, if you just want it to go away finally: # emit logs here

Respuesta original

Estás pensando en esto un poco de lado.

Tiene la intención de manejar la excepción; lo está gestionando configurando un indicador. Tal vez no te importa nada más (lo que parece una mala idea), pero si te importa hacer algo cuando se produce una excepción, entonces debes ser explícito al respecto.

El hecho de que esté configurando una variable, pero desea que la excepción continúe significa que lo que realmente desea es plantear su propia excepción específica, a partir de la excepción que se planteó:

class MyPkgException(Exception): pass class MyError(PyPkgException): pass # If there''s another exception type, you can also inherit from that def do_the_badness(): try: raise FileNotFoundError(''Or some other code that raises an error'') except FileNotFoundError as e: raise MyError(''File was not found, doh!'') from e finally: do_some_cleanup() try: do_the_badness() except MyError as e: print(''The error? Yeah, it happened'')

Esto resuelve:

  • Manejando explícitamente la (s) excepción (es) que está tratando de manejar
  • Hacer que los restos de la pila y las excepciones originales estén disponibles
  • Permitir que su código maneje la excepción original en otro lugar para manejar su excepción lanzada
  • Permitir que un código de manejo de excepciones de primer nivel simplemente capture MyPkgException para capturar todas sus excepciones, de modo que pueda registrar algo y salir con un estado agradable en lugar de un rastro feo de la pila

Puede asignar fácilmente su excepción atrapada a una variable y usarla en el bloque finally, por ejemplo:

>>> x = 1 >>> error = None >>> try: ... x.foo() ... except Exception as e: ... error = e ... finally: ... if error is not None: ... print(error) ... ''int'' object has no attribute ''foo''


Si fuera yo, haría una pequeña reordenación de tu código.

raised = False try: # funky code except HandleThis: # handle it raised = True except Exception as ex: # Don''t Handle This raise ex finally: if raised: logger.info(''funky code was raised'')

He colocado la asignación booleana planteada fuera de la declaración de prueba para garantizar el alcance y he convertido la sentencia de excepción final en un controlador de excepción general para las excepciones que no desea manejar.

Este estilo determina si tu código falló. Otro enfoque me puede ayudar a determinar cuándo tu código tiene éxito.

success = False try: # funky code success = True except HandleThis: # handle it pass except Exception as ex: # Don''t Handle This raise ex finally: if success: logger.info(''funky code was successful'') else: logger.info(''funky code was raised'')


raised = True try: funky code raised = False except HandleThis: # handle it finally: logger.info(''funky code raised %s'', raised)

Dada la información de antecedentes adicional agregada a la pregunta sobre la selección de un nivel de registro, esto parece muy fácil de adaptar al caso de uso previsto:

mylog = WARNING try: funky code mylog = DEBUG except HandleThis: # handle it finally: mylog(...)