Catch "before / after function call" events for all functions of the class

Is it possible to catch events "before / after calling the function" for all functions of the class without decorating each of these functions? Maybe some cool decorator? In other words, for such code, I would like to get the following output:

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 

I need this not for tracing. In a class working with asynchronous functions, I need to know if any function was called before the completion of another function.

+3
source share
2 answers

Yes, you can write a class decorator; The following allows you to decorate each of the class functions:

 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 

The above class decorator applies this function decorator to all called objects of the class.

Let's say you have a decorator that prints the name of the called function before and after:

 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 

then the class decorator can be applied with:

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

Demo:

 >>> @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 
+13
source

If you don’t want to decorate all the classes for which you want to use this function, you can try metaprogramming to change the methods at creation time to start the preliminary / post operation, the details are in the answer to this question How to start the method before / after all class function calls with arguments passed?

+1
source

Source: https://habr.com/ru/post/1203388/


All Articles