2010-11-22 15 views
14

Tengo una función de python que puede generar una excepción. La persona que llama capta la excepción y la trata. Ahora me gustaría añadir un decorador a la función que también detecta la excepción, hace algo de manejo, pero luego re-lanza la excepción para permitir que la llamada original manejarlo. Esto funciona, excepto que cuando la persona que llama original muestra la pila de llamadas de la excepción, muestra la línea en el decorador donde se volvió a subir, no donde originalmente se produjo. Código de ejemplo:¿Cómo atrapo una excepción en un decorador pero le permito a la persona que llama captarlo también?

import sys,traceback 

def mydec(func): 
    def dec(): 
     try: 
      func() 
     except Exception,e: 
      print 'Decorator handled exception %s' % e 
      raise e 
    return dec 

@mydec 
def myfunc(): 
    x = 1/0 

try: 
    myfunc() 
except Exception,e: 
    print 'Exception: %s' % e 
    type,value,tb = sys.exc_info() 
    traceback.print_tb(tb) 

La salida es:

Decorator handled exception integer division or modulo by zero 
Exception: integer division or modulo by zero 
    File "allbug.py", line 20, in <module> 
    myfunc() 
    File "allbug.py", line 9, in dec 
    raise e 

Me gustaría que el decorador para ser capaz de manejar la excepción sino la de rastreo debería indicar la línea x = 1/0 lugar de la línea raise. ¿Cómo puedo hacer esto?

Respuesta

17

sólo tiene que utilizar raise; (es decir, no plantean nada específico, simplemente raise;) en un bloque catch volver a subir sin excepción "reajustar" el rastreo.

+0

Para que quede claro, sólo tiene que utilizar una declaración desnudo "aumentar". No especifique qué recaudar. – drxzcl

+1

¡Gracias! Lo aceptaré tan pronto como me permita ... –

+1

@Graeme: No es necesario que te golpees la cabeza. Esta no es una solución obvia que podría haber pensado por sí mismo :) – delnan

8

acabo de escribieron una clase similar a lo que está haciendo, pero con un poco más opciones disponibles. Aquí está:

class ErrorIgnore(object): 
    def __init__(self, errors, errorreturn = None, errorcall = None): 
     self.errors = errors 
     self.errorreturn = errorreturn 
     self.errorcall = errorcall 

    def __call__(self, function): 
     def returnfunction(*args, **kwargs): 
     try: 
      return function(*args, **kwargs) 
     except Exception as E: 
      if type(E) not in self.errors: 
       raise E 
      if self.errorcall is not None: 
       self.errorcall(E, *args, **kwargs) 
      return self.errorreturn 
     return returnfunction 

uso común sería algo así como:

def errorcall(E, *args): 
    print 'exception skipped', E 

@ErrorIgnore(errors = [ZeroDivisionError, ValueError], errorreturn = None, errorcall = errorcall) 
def myfunction(stuff): 
    # do stuff 
    # return stuff 
    # the errors shown are skipped 
Cuestiones relacionadas