2011-03-21 11 views
11

Al manejar excepciones en python, me encuentro repitiendo código con bastante frecuencia. El patrón básico es algo de la forma:¿Cuáles son algunas formas elegantes de abstraer el manejo repetitivo de excepciones en python?

try: 
    action_here() 
except CommonException1: 
    Action_always_taken_for_CommonException1() 
except CommonException2: 
    Action_always_taken_for_CommonException2() 
except Exception: 
    Default_action_always_taken() 

Lo que me gustaría hacer es de alguna forma abstracta el código repetitivo a una función o clase. Yo sé una manera de hacerlo es llamar a una función de gestión de excepciones con el objeto de excepción, tales como:

try: 
    action_here() 
except Exception as e: 
    handle_exception(e) 

Luego, en esta función determinar la excepción basada en la clase.

def handle_exception(e): 
    if type(e) == type(CommonException1()): 
    Action_always_taken_for_CommonException1() 
    elif type(e) == type(CommonException2()): 
    Action_always_taken_for_CommonException2()) 
    else: 
    Default_action_always_taken() 

Esto, sin embargo, se siente torpe y poco elegante. Entonces mi pregunta es, ¿cuáles son algunas otras alternativas para manejar el manejo repetitivo de excepciones?

+0

que parece tan elegante como se puede conseguir. ¿Qué estabas pensando en usar? – Blender

+0

@Blender Mi solución fue la única solución viable que se me ocurrió. Estaba preguntando si alguien sabía de una mejor solución. – cledoux

Respuesta

19

Esta situación es uno de los principales casos de uso de gestores de contexto y la sentencia with:

from __future__ import with_statement # Needed in 2.5, but not in 2.6 or later 

from contextlib import contextmanager 

@contextmanager 
def handle_exceptions(): 
    try: 
     yield # Body of the with statement effectively runs here 
    except CommonException1: 
     Action_always_taken_for_CommonException1() 
    except CommonException2: 
     Action_always_taken_for_CommonException2() 
    except Exception: 
     Default_action_always_taken() 

# Used as follows 
with handle_exceptions(): 
    action_here() 
+0

Esto es exactamente el tipo de cosa que estaba buscando. ¡Gracias! – cledoux

6

Si no le gusta las repetidas if/elseif bloques, podría poner sus manijas en un diccionario, introducido por tipo:

handlers = { type(CommonException1()) : Action_always_taken_forCommonException1, 
      type(CommonException2()) : Action_always_taken_forCommonException2 } 

def handle_exception(te): 
    if te in handlers: 
    handlers[te]() 
    else: 
    Default_action() 

que luego se podría ejecutar con:

try: 
    action_here() 
except Exception as e: 
    handle_exception(type(e)) 

Además: Si se encuentra escribiendo estos bloques de prueba con frecuencia, entonces podría escribir su propio administrador de contexto (se e here). En el lado action_here(), el código sería el siguiente aspecto:

with my_error_handling_context(): 
    action_here1() 
    action_here2() 

En este caso, el código handle_exception sería esencialmente __exit__ método de su gestor de contexto (que siempre se van pasando las excepciones planteadas durante el con el bloque).

+0

El administrador de contexto es exactamente el tipo de solución que estaba buscando. ¡Gracias! – cledoux

5

Aunque una solución utilizando un gestor de contexto (como se propone por otros) es el más elegante, y sería lo yo recomendaría también, me gustaría señalar que la función de su handle_exception se podría escribir más elegante por la re-lanzar la excepción:

def handle_exception(e): 
    try: 
    raise e 
    except CommonException1: 
    Action_always_taken_for_CommonException1() 
    except CommonException2: 
    Action_always_taken_for_CommonException2() 
    except Exception: 
    Default_action_always_taken() 
+0

Gracias, nunca pensé en eso yo mismo. – cledoux

Cuestiones relacionadas