Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
313 views
in Technique[技术] by (71.8m points)

python - Catch "before/after function call" events for all functions in class

Is there any possibility to catch "before/after function call" events for all functions in class, without decorating each of these functions? May be some class decorator? In other words, for such code, I would like to get 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 it not for tracing. In class working with asynchronous functions, I need to know if some function were called before other function were finished.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Yes, you can write a class decorator; the following will allow you to decorate each of the functions in the class:

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 a given function decorator to all callables on a class.

Say you have a decorator that prints the name of the function being called 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 could 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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...