Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a parameter to the decorator in python

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

like image 283
ZEE Avatar asked Mar 25 '13 21:03

ZEE


People also ask

How do you pass a value to a decorator in Python?

Use a decorator factory function to pass parameters to a decorator. To pass parameters to a decorator, create a decorator factory function that accepts the desired parameters. When called, the decorator factory should return the specific decorator that will be applied to the target function.

How do you declare a decorator in Python?

To define a general purpose decorator that can be applied to any function we use args and **kwargs . args and **kwargs collect all positional and keyword arguments and stores them in the args and kwargs variables. args and kwargs allow us to pass as many arguments as we would like during function calls.


1 Answers

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

like image 123
Andrew Clark Avatar answered Oct 06 '22 18:10

Andrew Clark