How do I pass extra arguments to a Python decorator?
我有一个像下面这样的装饰师。
1 2 3 4 5 6 7 | def myDecorator(test_func): return callSomeWrapper(test_func) def callSomeWrapper(test_func): return test_func @myDecorator def someFunc(): print 'hello' |
我想增强这个装饰器以接受下面这样的另一个论点
1 2 3 4 5 6 7 | def myDecorator(test_func,logIt): if logIt: print"Calling Function:" + test_func.__name__ return callSomeWrapper(test_func) @myDecorator(False) def someFunc(): print 'Hello' |
号
但这段代码给出了错误,
TypeError: myDecorator() takes exactly 2 arguments (1 given)
号
为什么函数不是自动传递的?如何将函数显式传递给decorator函数?
由于您像函数一样调用decorator,因此它需要返回另一个函数,即实际的decorator:
1 2 3 4 5 | def my_decorator(param): def actual_decorator(func): print("Decorating function {}, with parameter {}".format(func.__name__, param)) return function_wrapper(func) # assume we defined a wrapper somewhere return actual_decorator |
外部函数将得到您显式传递的任何参数,并且应该返回内部函数。内部函数将传递要修饰的函数,并返回修改后的函数。
通常,您希望装饰器通过将函数包装在包装函数中来更改函数行为。下面是一个示例,可以选择在调用函数时添加日志记录:
1 2 3 4 5 6 7 8 9 | def log_decorator(log_enabled): def actual_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): if log_enabled: print("Calling Function:" + func.__name__) return func(*args, **kwargs) return wrapper return actual_decorator |
号
示例用法:
1 2 3 4 5 6 7 | >>> @log_decorator(True) ... def f(x): ... return x+1 ... >>> f(4) Calling Function: f 5 |
只是为了提供一个不同的观点:语法
1 2 | @expr def func(...): #stuff |
。
等于
1 2 | def func(...): #stuff func = expr(func) |
特别是,
1 2 3 | dec = decorator_factory(*args) @dec def func(...): |
。
然后可以缩短为
1 2 | @decorator_factory(*args) def func(...): |
。
当然,因为它看起来像
只想添加一些有用的技巧,使修饰参数成为可选的。它还可以重用装饰器并减少嵌套。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import functools def myDecorator(test_func=None,logIt=None): if not test_func: return functools.partial(myDecorator, logIt=logIt) @functools.wraps(test_func) def f(*args, **kwargs): if logIt==1: print 'Logging level 1 for {}'.format(test_func.__name__) if logIt==2: print 'Logging level 2 for {}'.format(test_func.__name__) return test_func(*args, **kwargs) return f #new decorator myDecorator_2 = myDecorator(logIt=2) @myDecorator(logIt=2) def pow2(i): return i**2 @myDecorator def pow3(i): return i**3 @myDecorator_2 def pow4(i): return i**4 print pow2(2) print pow3(2) print pow4(2) |
只是做装饰的另一种方式。我觉得这样最容易把我的头包起来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class NiceDecorator: def __init__(self, param_foo='a', param_bar='b'): self.param_foo = param_foo self.param_bar = param_bar def __call__(self, func): def my_logic(*args, **kwargs): # whatever logic your decorator is supposed to implement goes in here print('pre action baz') print(self.param_bar) # including the call to the decorated function (if you want to do that) result = func(*args, **kwargs) print('post action beep') return result return my_logic # usage example from here on @NiceDecorator(param_bar='baaar') def example(): print('example yay') example() |
。