I have a decorator like below.
我有一个像下面的装饰。
def myDecorator(test_func):
return callSomeWrapper(test_func)
def callSomeWrapper(test_func):
return test_func
@myDecorator
def someFunc():
print 'hello'
I want to enhance this decorator to accept another argument like below
我想增强这个装饰器来接受下面的另一个参数
def myDecorator(test_func,logIt):
if logIt:
print "Calling Function: " + test_func.__name__
return callSomeWrapper(test_func)
@myDecorator(False)
def someFunc():
print 'Hello'
But this code gives the error,
但是这段代码给出了错误,
TypeError: myDecorator() takes exactly 2 arguments (1 given)
TypeError:myDecorator()只需2个参数(给定1个)
Why is the function not automatically passed? How do I explicitly pass the function to the decorator function?
为什么函数不会自动通过?如何将函数显式传递给装饰器函数?
4 个解决方案
#1
118
Since you are calling the decorator like a function, it needs to return another function which is the actual decorator:
因为您像函数一样调用装饰器,所以它需要返回另一个函数,它是实际的装饰器:
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
The outer function will be given any arguments you pass explicitly, and should return the inner function. The inner function will be passed the function to decorate, and return the modified function.
外部函数将被赋予您明确传递的任何参数,并应返回内部函数。内部函数将传递函数进行修饰,并返回修改后的函数。
Usually you want the decorator to change the function behavior by wrapping it in a wrapper function. Here's an example that optionally adds logging when the function is called:
通常,您希望装饰器通过将其包装在包装函数中来更改函数行为。这是一个示例,可以选择在调用函数时添加日志记录:
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
The functools.wraps
call copies things like the name and docstring to the wrapper function, to make it more similar to the original function.
functools.wraps调用将名称和文档字符串等内容复制到包装函数,使其更类似于原始函数。
Example usage:
用法示例:
>>> @log_decorator(True)
... def f(x):
... return x+1
...
>>> f(4)
Calling Function: f
5
#2
36
Just to provide a different viewpoint: the syntax
只是为了提供一个不同的观点:语法
@expr
def func(...): #stuff
is equivalent to
相当于
def func(...): #stuff
func = expr(func)
In particular, expr
can be anything you like, as long as it evaluates to a callable. In particular particular, expr
can be a decorator factory: you give it some parameters and it gives you a decorator. So maybe a better way to understand your situation is as
特别是,expr可以是你喜欢的任何东西,只要它的计算结果是可调用的。特别是,expr可以是一个装饰工厂:你给它一些参数,它给你一个装饰。所以也许更好的方式来了解你的情况就像
dec = decorator_factory(*args)
@dec
def func(...):
which can then be shortened to
然后可以缩短为
@decorator_factory(*args)
def func(...):
Of course, since it looks like decorator_factory
is a decorator, people tend to name it to reflect that. Which can be confusing when you try to follow the levels of indirection.
当然,因为看起来decorator_factory是一个装饰器,人们倾向于将其命名为反映。当您尝试遵循间接级别时,这可能会令人困惑。
#3
14
Just want to add some usefull trick that will allow to make decorator arguments optional. It will also alows to reuse decorator and decrease nesting
只是想添加一些有用的技巧,允许装饰器参数可选。它也将重用装饰器并减少嵌套
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)
#4
1
Just another way of doing decorators. I find this way the easiest to wrap my head around.
只是做装饰器的另一种方式。我发现这种方式最容易缠头。
import functools
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):
@functools.wraps(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()
#1
118
Since you are calling the decorator like a function, it needs to return another function which is the actual decorator:
因为您像函数一样调用装饰器,所以它需要返回另一个函数,它是实际的装饰器:
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
The outer function will be given any arguments you pass explicitly, and should return the inner function. The inner function will be passed the function to decorate, and return the modified function.
外部函数将被赋予您明确传递的任何参数,并应返回内部函数。内部函数将传递函数进行修饰,并返回修改后的函数。
Usually you want the decorator to change the function behavior by wrapping it in a wrapper function. Here's an example that optionally adds logging when the function is called:
通常,您希望装饰器通过将其包装在包装函数中来更改函数行为。这是一个示例,可以选择在调用函数时添加日志记录:
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
The functools.wraps
call copies things like the name and docstring to the wrapper function, to make it more similar to the original function.
functools.wraps调用将名称和文档字符串等内容复制到包装函数,使其更类似于原始函数。
Example usage:
用法示例:
>>> @log_decorator(True)
... def f(x):
... return x+1
...
>>> f(4)
Calling Function: f
5
#2
36
Just to provide a different viewpoint: the syntax
只是为了提供一个不同的观点:语法
@expr
def func(...): #stuff
is equivalent to
相当于
def func(...): #stuff
func = expr(func)
In particular, expr
can be anything you like, as long as it evaluates to a callable. In particular particular, expr
can be a decorator factory: you give it some parameters and it gives you a decorator. So maybe a better way to understand your situation is as
特别是,expr可以是你喜欢的任何东西,只要它的计算结果是可调用的。特别是,expr可以是一个装饰工厂:你给它一些参数,它给你一个装饰。所以也许更好的方式来了解你的情况就像
dec = decorator_factory(*args)
@dec
def func(...):
which can then be shortened to
然后可以缩短为
@decorator_factory(*args)
def func(...):
Of course, since it looks like decorator_factory
is a decorator, people tend to name it to reflect that. Which can be confusing when you try to follow the levels of indirection.
当然,因为看起来decorator_factory是一个装饰器,人们倾向于将其命名为反映。当您尝试遵循间接级别时,这可能会令人困惑。
#3
14
Just want to add some usefull trick that will allow to make decorator arguments optional. It will also alows to reuse decorator and decrease nesting
只是想添加一些有用的技巧,允许装饰器参数可选。它也将重用装饰器并减少嵌套
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)
#4
1
Just another way of doing decorators. I find this way the easiest to wrap my head around.
只是做装饰器的另一种方式。我发现这种方式最容易缠头。
import functools
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):
@functools.wraps(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()