Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scope of variables in python decorators - changing parameters

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?

like image 420
Zaar Hai Avatar asked Aug 22 '12 17:08

Zaar Hai


People also ask

How do I change the scope of a variable in Python?

@Reboot_87: you can't; the objects you're passing in are immutable and it's therefore impossible to change them, and you can't re-bind the names in the outer scope just based on what's passed in.

Can you modify a variable in Python?

Some values in python can be modified, and some cannot. This does not ever mean that we can't change the value of a variable – but if a variable contains a value of an immutable type, we can only assign it a new value. We cannot alter the existing value in any way.

Can Python decorators take arguments?

The decorator arguments are accessible to the inner decorator through a closure, exactly like how the wrapped() inner function can access f . And since closures extend to all the levels of inner functions, arg is also accessible from within wrapped() if necessary.

How do you pass a value dynamically in Python?

Dynamic Function Arguments We simply can make solve_for() accept *args and **kwargs then pass that to func() . Of course, you will need to handle the arguments in the function that will be called.


1 Answers

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.

like image 59
BrenBarn Avatar answered Oct 11 '22 23:10

BrenBarn