Atrapa excepciones dentro de una clase

¿Es posible escribir un controlador de excepciones para detectar los errores en tiempo de ejecución generados por TODOS los métodos en clase? Puedo hacerlo rodeando a cada uno con try / except:

class MyError(Exception): def __init__(self, obj, method): print 'Debug info:', repr(obj.data), method.__name__ raise class MyClass: def __init__(self, data): self.data = data def f1(self): try: all method code here, maybe failing at run time except: raise MyError(self, self.f1) 

Me pregunto si hay una manera más general de lograr lo mismo, para cualquier error que surja en cualquier parte de la clase. Me gustaría poder acceder a los datos de clase para imprimir información de depuración. Además, ¿cómo obtengo el nombre del método que falla (f1 en el ejemplo)?

Actualización : gracias a todos por las respuestas escandalosas, la idea del decorador parece ser el camino a seguir. Sobre el riesgo de atrapar TODAS las excepciones: una statement de raise en la twig de except debería volver a generar la excepción sin perder ninguna información, ¿no es así? Por eso lo puse en MyError también …

Advertencia: si quieres algo como esto, es probable que no … pero si realmente quieres …

Algo como:

 import functools def catch_exception(f): @functools.wraps(f) def func(*args, **kwargs): try: return f(*args, **kwargs) except Exception as e: print 'Caught an exception in', f.__name__ return func class Test(object): def __init__(self, val): self.val = val @catch_exception def calc(): return self.val / 0 t = Test(3) t.calc() 

Muestra cómo decorar funciones individuales. Luego, puede crear un decorador de clase para aplicar este decorador a cada método (tenga cuidado con los classmethod's de classmethod's / staticmethod's / staticmethod's etc.)

Suponiendo que tenga un decorador catch_exception como en la respuesta de @Jon Clement …

 class ErrorCatcher(type): def __new__(cls, name, bases, dct): for m in dct: if hasattr(dct[m], '__call__'): dct[m] = catch_exception(dct[m]) return type.__new__(cls, name, bases, dct) class Test(object): __metaclass__ = ErrorCatcher def __init__(self, val): self.val = val def calc(self): return self.val / 0 

La metaclase aplica catch_exception a todo lo que parece ser un método mientras define Test .


En respuesta a un comentario sobre los mensajes personalizados para cada método, uno podría adjuntar dicho mensaje (o incluso una función de callback para generar un mensaje) como un atributo:

 class Test(object): __metaclass__ = ErrorCatcher def __init__(self, val): self.val = val def calc(self): return self.val / 0 calc.msg = "Dividing by 0 is ill-advised" 

El decorador catch_exception buscaría un atributo msg en su argumento y lo usaría, si lo encuentra, para manejar la excepción.

Este enfoque podría extenderse; en lugar de una cadena, msg podría ser una asignación de tipos de excepción a cadenas. En cualquier caso, la cadena podría reemplazarse (con el apoyo de catch_exception , por supuesto) con una función de callback arbitraria que toma, por ejemplo, la excepción planteada como un argumento.

 def calc_handler(exc): # ... calc.callback = calc_handler 

Un decorador sería una buena solución aquí.

Aquí hay un ejemplo de cómo puedes hacerlo:

 import inspect def catch_exception_decorator(function): def decorated_function: try: function() except: raise MyError(self.__class__, inspect.stack()[1][3]) return decorated_function class MyClass(object): def __init__(self): ... @catch_exception_decorator def f1(self): ... 

@catch_exception_decorator en la parte superior de la función es un acceso directo para f1 = catch_exception_decorator(f1) .

En lugar de hacer uno mismo. clase , también puede acceder a los datos de clase desde la instancia, siempre y cuando no esté siguiendo las variables. inspect.stack () [1] [3] es el nombre de la función de la función actual. Puede utilizar estos para crear los atributos de excepción.