Detecta eventos de “llamada de función anterior / posterior” para todas las funciones en clase

¿Hay alguna posibilidad de capturar eventos de “llamada de función anterior / posterior” para todas las funciones en clase, sin decorar cada una de estas funciones? ¿Puede haber algún decorador de clase? En otras palabras, para dicho código, me gustaría obtener el siguiente resultado:

class Foo: def func1(): print('1') def func2(): print('2') c = Foo() c.func1() c.func2() # Output I would like to get: # func1 called # 1 # func1 finished # func2 called # 2 # func2 finished 

No lo necesito para el rastreo. En la clase que trabaja con funciones asíncronas, necesito saber si se llamó a alguna función antes de que se terminara otra.

Sí, puedes escribir un decorador de clase; Lo siguiente le permitirá decorar cada una de las funciones en la clase:

 def decorate_all_functions(function_decorator): def decorator(cls): for name, obj in vars(cls).items(): if callable(obj): try: obj = obj.__func__ # unwrap Python 2 unbound method except AttributeError: pass # not needed in Python 3 setattr(cls, name, function_decorator(obj)) return cls return decorator 

El decorador de clase anterior aplica un decorador de función dada a todos los callables en una clase.

Digamos que tienes un decorador que imprime el nombre de la función que se llama antes y después:

 from functools import wraps def print_on_call(func): @wraps(func) def wrapper(*args, **kw): print('{} called'.format(func.__name__)) try: res = func(*args, **kw) finally: print('{} finished'.format(func.__name__)) return res return wrapper 

entonces el decorador de clase podría ser aplicado con:

 @decorate_all_functions(print_on_call) class Foo: def func1(self): print('1') def func2(self): print('2') 

Manifestación:

 >>> @decorate_all_functions(print_on_call) ... class Foo: ... def func1(self): ... print('1') ... def func2(self): ... print('2') ... >>> c = Foo() >>> c.func1() func1 called 1 func1 finished >>> c.func2() func2 called 2 func2 finished 

Si no desea decorar todas las clases que desea que tengan esta funcionalidad, puede probar la metaprogtwigción para modificar los métodos durante la creación para ejecutar una operación pre / post, los detalles se encuentran en la respuesta a esta pregunta Cómo ejecutar una ¿Método antes / después de todas las funciones de clase llamadas con argumentos pasados?