kingrz
kingrz

Reputation: 23

Decorating a function with parameters not working as expected

I have a decorator that has to add HTML tags to a string. The decorator works fine if it has to wrap a fixed string.

def tagger(fn):
    def wrapper(*x):
        return "<strong>" + fn() + "</strong>"
    return wrapper

@tagger
def foo():
    return 'Hello'

print(foo())     

But if I remove the fixed string and add a parameter to the function foo(), the decorator doesn't work.

def tagger(fn):
    def wrapper(*x):
        return "<strong>" + fn() + "</strong>"
    return wrapper

@tagger
def foo(x):
    return str(x)

print(foo('Hello'))     

What am I doing wrong?

Upvotes: 1

Views: 305

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1121494

You never pass on the parameter. The expression fn() in the wrapper is a call to the original, decorated function, but you don't pass the arguments on.

Your decorator wrapper accepts arbitrary positional arguments as *x, pass those into the fn() call:

def tagger(fn):
    def wrapper(*x):
        return "<strong>" + fn(*x) + "</strong>"
    return wrapper

For completion sake, you also want to pass on keyword arguments, and use the more common args and kwargs names for these variables:

def tagger(fn):
    def wrapper(*args, **kwargs):
        return "<strong>" + fn(*args, **kwargs) + "</strong>"
    return wrapper

Now the decorator can be used on functions that take keyword arguments as well.

Upvotes: 2

JarroVGIT
JarroVGIT

Reputation: 5279

You missed forwarding any *args into the fn() call.

def tagger(fn):
        def wrapper(*x):
               return "<strong>" + fn(*x) + "</strong>"  # <-- This will call foo(*x)
        return wrapper
@tagger
def foo(x):
    return str(x)

print(foo('Hello'))

Upvotes: 3

Related Questions