Why is this decorator with a parameter not working?
def decAny( f0 ):
def wrapper( s0 ):
return \"<%s> %s %s>\" % ( any, f0(), any
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.
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.
You can read up about functools.wraps()
here:
http://docs.python.org/2/library/functools.html#functools.wraps
There is a good sample from "Mark Lutz - Learning Python" book:
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