¿Es posible saber si hubo una excepción una vez que estás en la finally final? 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.
Dado que algunos comentarios solicitan menos "M" en el MCVE, aquí hay más información sobre el caso de uso. El problema real es sobre la escalada de los niveles de registro.
logger.exception en un bloque de excepción no es útil aquí.Por lo tanto, el código se ejecuta en un contexto de captura de registro (que configura controladores personalizados para interceptar registros) y parte de la información de depuración se vuelve a registrar retrospectivamente:
try: with LogCapture() as log: funky_code() # <-- third party badness finally: # log events are buffered in memory. if there was an exception, # emit everything that was captured at a WARNING level for record in log.captured: if <there was an exception>: log_fn = mylogger.warning else: log_fn = getattr(mylogger, record.levelname.lower()) log_fn(record.msg, record.args)Podría usar un administrador 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')Todavía es una variable adicional, pero probablemente sea mucho más fácil de reutilizar si desea usarla en varios lugares. Y no es necesario que lo cambie usted mismo.
En caso de que no desee el administrador de contexto, invertiría la lógica del activador y lo alternaría solo en caso de que no haya ocurrido ninguna excepción. De esa manera, no necesita un caso de except para las 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 arroje 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 de "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 coloca al final de su try (como sugirieron otras respuestas aquí), pero prefiero la cláusula else porque tiene más significado ("ese código debe ejecutarse solo si no hubo una excepción en el bloque try ") y puede ser más fácil de mantener a largo plazo. Aunque todavía es más para mantener que el administrador de contexto porque la variable se configura y alterna en diferentes lugares.
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 capturó en ningún bloque de except o que se generó dentro de un bloque de 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, eg NOT a HandleThis exception print('funky code 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 fondo 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(...)Puede asignar fácilmente su excepción detectada a una variable y usarla en el bloque finalmente, 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'