https://gist.github.com/skatenerd/72281cadd2ae3e44d6cf
For some reason, stashing the variable inside of a list will fix the variable resolution..?
http://stackoverflow.com/questions/4851463/python-closure-wr...
https://gist.github.com/skatenerd/72281cadd2ae3e44d6cf
For some reason, stashing the variable inside of a list will fix the variable resolution..?
http://stackoverflow.com/questions/4851463/python-closure-wr...
Turns out the problem is the +=, perhaps it would be a bit clearer if written as:
grand_total = grand_total + to_add
which introduces a new local variable called grand_total shadowing the outer one. So it's straightforward enough, the pitfall is missing the shadowing.Note that you could use the outer grand_total without problems if you don't shadow it, e.g. using it as an rvalue (is that a pythonic term?) , and also note Python 3 provides a 'nonlocal' keyword to let you pull the outer variable into scope so it won't be shadowed.
Python will by default shadow variables in an enclosing scope instead of overwriting them during assignment, to prevent accidental introduction of global state. You can use the "global" keyword to force overwriting the outer variable. The list hack also works because it is a mutable data structure, but I wouldn't recommend it.
This means that in the following code, "x" will refer to a local variable for the whole function body:
x = "foo"
def f():
print(x)
x = 42
f()
...so instead of printing "foo" (the value of the global variable) the print statement will raise an exception: UnboundLocalError: local variable 'x' referenced before assignment
If you meant it to refer to a global variable or something in the parent scope, simply put "global x" or "nonlocal x", respectively, at the start of the function. Again, that applies to the whole function body, so the assignment in this example would change the value of the global variable.nonlocal was added to fix this problem.
lists make a difference because they are a mutable container for other values, not because name resolution changes when you use them.
There are lots of other awful hacks:
def a2(start):
def a(v):
a.v+=v
return a.v
a.v=start
return a