Skip to content Skip to sidebar Skip to footer

Reassigning Parameters Within Decorators In Python

Consider a simple Python decorator with parameters: def decorator_factory(a=None): def decorator(func): def wrapper(*args, **kws): return func(*args, **kws)

Solution 1:

This is a scoping issue. By reassigning the name, the Python interpreter reserves the reassigned name for local usage, thus shadowing the previous value from the outer scopes, which results in the name being unbound if used before the first assignment.

The simplest solution to this is to never reassign a decorator parameter's name inside the wrapper(). Just use a different name throughout.

For example:

defdecorator_factory(a=None):
    defdecorator(func):
        defwrapper(*args, **kws):
            y = func(*args, **kws)
            a_ = y if a isNoneelse a
            return y + a_
        return wrapper
    return decorator


@decorator_factory()deffoo(x):
    return2 * x


print(foo(2))
# 8print(foo(3))
# 12

Note: the nonlocal statement would avoid raising the UnboundLocalError, BUT the value of the parameter will persist across multiple function calls, e.g.:

defdecorator_factory(a=None):
    defdecorator(func):
        defwrapper(*args, **kws):
            nonlocal a
            y = func(*args, **kws)
            a = y if a isNoneelse a
            return y + a
        return wrapper
    return decorator


@decorator_factory()deffoo(x):
    return2 * x


print(foo(2))
# 8print(foo(3))
# 10

The last foo() call gives 10 because the value of a=4 inside the decorated function comes from the previous foo() call.

Post a Comment for "Reassigning Parameters Within Decorators In Python"