简体   繁体   中英

Python - decorator manipulating attributes of target functions

My goal is to come up with a decorator that would accept functions with arbitrary number of params and change the target function's attributes. One example, I need an attribute in the target function which would contain execution length in seconds. I have tried to utilize functool's wraps method to preserve the attributes, but with no success. It only seems to preserve the initial attributes like __doc__ and __name__ , but I am not able to assign new value to non-existant attribute. I know that I could assign the duration attribute to wrapper before returning it, intead of func . But this is suitable only for those cases when we do not have to count for what happens inside the func, like in my case. So, here's my code:

import time
from functools import wraps

def my_dec(param):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            start = time.time()
            rs = func(*args, **kwargs)
            func.duration = time.time() - start
            return rs
        wrapper.a = 'a'
        return wrapper
    return decorator


@my_dec('Dec param')
def target_func(x):
    return x.upper()
target_func('test value')
print(target_func.duration)

Assigning to wrapper.duration works...

import time
from functools import wraps

def my_dec(param):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            start = time.time()
            rs = func(*args, **kwargs)
            wrapper.duration = time.time() - start
            return rs
        return wrapper
    return decorator


@my_dec('Dec param')
def target_func(x):
    return x.upper()
target_func('test value')
print(target_func.duration)

Alternative answer, if you want to avoid referencing the wrapper function within its own definition:

import time
from functools import wraps

def my_dec(param):
    def decorator(func):
        durations = []
        @wraps(func)
        def wrapper(*args, **kwargs):
            start = time.time()
            rs = func(*args, **kwargs)
            durations.append(time.time() - start)
            return rs
        wrapper.durations = durations
        return wrapper
    return decorator


@my_dec('Dec param')
def target_func(x):
    return x.upper()
target_func('test value')
print(target_func.durations)

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