简体   繁体   中英

Using a paramaterized decorator for recording methods in a class

I realize much ink has already been spilled on decorators, but I can't find another question which exactly covers this. I have a class, and I would like to 'tag' some of the methods in that class using a decorator. In theory this is straightforward since decorators run when the class is defined. However, I also need to record some user-entered parameters from this decorator. So something like this:

@classmethod
def record_func(cls, is_function_special):
    def wrapped(func):
        return func 
    cls.recorded_functions.append((func, is_function_special))
    return wrapped

class TestClass:
    recorded_functions = []

    @record_func(False)
    def func1():
        return 1

    @get_funcs(True)
    def func2():
        return 2

The idea being that I would then be able to use this TestClass.recorded_functions elsewhere.

The problem (maybe one of many) is that it is only the outer-level decorator (in this case, record_func rather than wrapped) that runs when the class is defined, which has the argument in its namespace but not the function. Is there some clever way to record both the argument and the function?

NB, I've made the decorator a classmethod in this example so that it's generalizable to other classes.

Any help appreciated.

I like this problem, I was working on a decorator package and I think this could be a great addition. However, let me know if this gets you going in the right direction. It can record every method call, record its args, and kwargs. Then you can do any analytics/aggregation with those results you need.

import functools


def bvr_start(arg=None):
    def bvr_start_decorator(func):
        @functools.wraps(func)
        def bvr_start_wrapper(*args, **kwargs):
            msg = ("STARTED | "
                   "FUNCTION: {} | "
                   "ARGS: {} | "
                   "KWARGS: {} ").format(func.__name__,
                                         args,
                                         kwargs)

            args[0].called_functions.append(msg)


            print(msg)

            return_value = func(*args, **kwargs)
            return return_value
        return bvr_start_wrapper

    if callable(arg):
        return bvr_start_decorator(arg)

    return bvr_start_decorator


class Hello:

    called_functions = []

    @bvr_start
    def test_function_one(self):
        print("Inside my function one")

    @bvr_start
    def test_function_two(self, x):
        print("Inside my function two")


    @bvr_start
    def test_function_three(self, y):
        print("Inside my function three")

hello = Hello()

hello.test_function_one()
hello.test_function_two(4)
hello.test_function_three(y=5)

print("Now print out your called functions")

for called_function in hello.called_functions:
    print(called_function)

Now the result of this is:

STARTED | FUNCTION: test_function_one | ARGS: (<__main__.Hello object at 0x1038ef2d0>,) | KWARGS: {} 
Inside my function one

STARTED | FUNCTION: test_function_two | ARGS: (<__main__.Hello object at 0x1038ef2d0>, 4) | KWARGS: {} 
Inside my function two

STARTED | FUNCTION: test_function_three | ARGS: (<__main__.Hello object at 0x1038ef2d0>,) | KWARGS: {'y': 5} 
Inside my function three

Now print out your called functions

STARTED | FUNCTION: test_function_one | ARGS: (<__main__.Hello object at 0x1038ef2d0>,) | KWARGS: {} 

STARTED | FUNCTION: test_function_two | ARGS: (<__main__.Hello object at 0x1038ef2d0>, 4) | KWARGS: {} 

STARTED | FUNCTION: test_function_three | ARGS: (<__main__.Hello object at 0x1038ef2d0>,) | KWARGS: {'y': 5}

Now you have a record of the function and the argument. And you can do some more dict like formatting on the final list of called_functions to count how many times each was called with what!

Thanks, and let me know if this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM