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"