Why is this decorator with a parameter not working?
为什么这个装饰器的参数不起作用?
def decAny( f0 ):
def wrapper( s0 ):
return "<%s> %s </%s>" % ( any, f0(), any )
return wrapper
@decAny( 'xxx' )
def test2():
return 'test1XML'
print( test2() )
always gives me an error saying "str is not callable" it is trying to execute the return string inside the wrapper() instead of processing it and return the result string
总是给我一个错误,说“str不可调用”它试图在wrapper()中执行返回字符串而不是处理它并返回结果字符串
2 个解决方案
#1
15
Decorators are functions that return functions. When "passing a parameter to the decorator" what you are actually doing is calling a function that returns a decorator. So decAny()
should be a function that returns a function that returns a function.
装饰器是返回函数的函数。当“将参数传递给装饰器”时,您实际在做的是调用返回装饰器的函数。所以decAny()应该是一个返回一个返回函数的函数的函数。
It would look something like this:
它看起来像这样:
import functools
def decAny(tag):
def dec(f0):
@functools.wraps(f0)
def wrapper(*args, **kwargs):
return "<%s> %s </%s>" % (tag, f0(*args, **kwargs), tag)
return wrapper
return dec
@decAny( 'xxx' )
def test2():
return 'test1XML'
Example:
>>> print(test2())
<xxx> test1XML </xxx>
Note that in addition to fixing the specific problem you were hitting I also improved your code a bit by adding *args
and **kwargs
as arguments to the wrapped function and passing them on to the f0
call inside of the decorator. This makes it so you can decorate a function that accepts any number of positional or named arguments and it will still work correctly.
请注意,除了修复您遇到的特定问题之外,我还通过添加* args和** kwargs作为包装函数的参数并将它们传递给装饰器内部的f0调用来改进代码。这使得它可以装饰一个接受任意数量的位置或命名参数的函数,它仍然可以正常工作。
You can read up about functools.wraps()
here:
http://docs.python.org/2/library/functools.html#functools.wraps
你可以在这里阅读functools.wraps():http://docs.python.org/2/library/functools.html#functools.wraps
#2
1
There is a good sample from "Mark Lutz - Learning Python" book:
“Mark Lutz - 学习Python”一书有很好的样本:
def timer(label=''):
def decorator(func):
def onCall(*args): # Multilevel state retention:
... # args passed to function
func(*args) # func retained in enclosing scope
print(label, ... # label retained in enclosing scope
return onCall
return decorator # Returns the actual decorator
@timer('==>') # Like listcomp = timer('==>')(listcomp)
def listcomp(N): ... # listcomp is rebound to new onCall
listcomp(...) # Really calls onCall
#1
15
Decorators are functions that return functions. When "passing a parameter to the decorator" what you are actually doing is calling a function that returns a decorator. So decAny()
should be a function that returns a function that returns a function.
装饰器是返回函数的函数。当“将参数传递给装饰器”时,您实际在做的是调用返回装饰器的函数。所以decAny()应该是一个返回一个返回函数的函数的函数。
It would look something like this:
它看起来像这样:
import functools
def decAny(tag):
def dec(f0):
@functools.wraps(f0)
def wrapper(*args, **kwargs):
return "<%s> %s </%s>" % (tag, f0(*args, **kwargs), tag)
return wrapper
return dec
@decAny( 'xxx' )
def test2():
return 'test1XML'
Example:
>>> print(test2())
<xxx> test1XML </xxx>
Note that in addition to fixing the specific problem you were hitting I also improved your code a bit by adding *args
and **kwargs
as arguments to the wrapped function and passing them on to the f0
call inside of the decorator. This makes it so you can decorate a function that accepts any number of positional or named arguments and it will still work correctly.
请注意,除了修复您遇到的特定问题之外,我还通过添加* args和** kwargs作为包装函数的参数并将它们传递给装饰器内部的f0调用来改进代码。这使得它可以装饰一个接受任意数量的位置或命名参数的函数,它仍然可以正常工作。
You can read up about functools.wraps()
here:
http://docs.python.org/2/library/functools.html#functools.wraps
你可以在这里阅读functools.wraps():http://docs.python.org/2/library/functools.html#functools.wraps
#2
1
There is a good sample from "Mark Lutz - Learning Python" book:
“Mark Lutz - 学习Python”一书有很好的样本:
def timer(label=''):
def decorator(func):
def onCall(*args): # Multilevel state retention:
... # args passed to function
func(*args) # func retained in enclosing scope
print(label, ... # label retained in enclosing scope
return onCall
return decorator # Returns the actual decorator
@timer('==>') # Like listcomp = timer('==>')(listcomp)
def listcomp(N): ... # listcomp is rebound to new onCall
listcomp(...) # Really calls onCall