5

I have the following decorator with parameters:

from functools import wraps
def pdecor(p):
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            p -= 1
            return fn(*args, **wargs)
        return wrapper
    return decorator

Trying to use the decorator results in :

>>> @pdecor(1)
... def run(): pass
...
>>> run()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in wrapper
UnboundLocalError: local variable 'p' referenced before assignment
>>>

Why can't I change the p?

Zaar Hai
  • 9,152
  • 8
  • 37
  • 45
  • possible duplicate of [Python variable scope question](http://stackoverflow.com/questions/370357/python-variable-scope-question) –  Aug 22 '12 at 17:24
  • See http://stackoverflow.com/questions/8447947/is-it-possible-to-modify-variable-in-python-that-is-in-outer-but-not-global-sc – Danica Aug 22 '12 at 17:24

1 Answers1

10

Because you assign to p inside wrapper, Python treats the p inside wrapper as local to wrapper. In Python 3 you can use nonlocal p to mark p as referenced from an outer scope. In Python 2 there is no way to assign to the intermediate p, although you can get a reference to the same value by passing it into the nested functions as a keyword argument (e.g., def decorator(fn, p=p)).

However, it's not clear what you're getting at with this anyway. p is already only local to pdecor. No code outside pdecor can access p, so decrementing it won't have any effect on any code elsewhere. So whether you can decrement p or not, it won't really accomplish anything.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • Originally I want to write a "retry" decorator that retries running function given amount of times. So I would try running `fn` and decrement `p` it `fn` raises exception until either I'm out of `p` retries or `fn` succeeds. However now I'm happy that Python did not let me doing so, otherwise all executions of the decorated function would share the same retry counter, right? – Zaar Hai Aug 22 '12 at 20:02