Strange Scoping in Nested Functions [duplicate] - python

This question already has answers here:
Python nested functions variable scoping [duplicate]
(10 answers)
Closed 5 years ago.
I have a two nested python functions, which look like this:
def outer():
t = 0
def inner():
t += 1
print(t)
inner()
Trying to call outer results in the following error:
>>> outer()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "sally.py", line 6, in outer
inner()
File "sally.py", line 4, in inner
t += 1
UnboundLocalError: local variable 't' referenced before assignment
I thought adding the line global t before t += 1 would help, except it didn't.
Why is this happening? How do I get around this problem, other than passing t to inner everytime I call it?

If using python 3, then using the nonlocal keyword would let the interpreter know to use the outer() function's scope for t:
def outer():
t = 0
def inner():
nonlocal t
t += 1
print(t)
inner()
If using python 2, then you can't directly assign to the variable, or it will make the interpreter create a new variable t which will hide the outer variable. You could pass in a mutable collection and update the first item:
def outer():
t = [0]
def inner():
t[0] += 1
print(t[0])
inner()

Related

Why Python list doesn't have scope limitation (while integer has)? [duplicate]

This question already has answers here:
python variable referenced before assignment int vs array
(2 answers)
Closed 3 years ago.
What I mean is, for an integer:
>>> a = 2
>>> def b():
... a += 1
...
>>> b()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in b
UnboundLocalError: local variable 'a' referenced before assignment
While for a list (or say for a list element):
>>> a = [0]
>>> def b():
... a[0] += 1
...
>>> b()
>>> a[0]
1
In the example with the int, Python is attempting to assign something to a in the function b() so it identifies a as a "local" variable in the function. And since the variable a is not yet defined, the interpreter throws the error.
In the example with the list, Python is not attempting to assign anything to a, so the interpreter identifies it as a "global" variable. Yes, it is modifying the values inside the list, but the reference to the list object named a hasn't changed.

UnboundLocalError: local variable 'sum' referenced before assignment [duplicate]

This question already has answers here:
UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)
(14 answers)
Closed 16 days ago.
Code1:
# coding:utf-8
sum = 5
def add(x, y):
print sum
sum = x + y
if __name__ == '__main__':
add(7, 8)
When I run the code above, I got the following error:
ssspure:python ssspure$ python test.py
Traceback (most recent call last):
File "test.py", line 11, in <module>
add(7, 8)
File "test.py", line 6, in add
print sum
UnboundLocalError: local variable 'sum' referenced before assignment
Code2:
# coding:utf-8
sum = 5
def add(x, y):
sum = x + y
print sum
if __name__ == '__main__':
add(7, 8)
I can run code2 successfully.
I only moved the print sum below "sum = x + y" statement. Why did Code1 fail but Code2 runs successfully?
For code1:
You didn't declare sum. The sum you defined outside of the add function has no impact to the sum in you add function.
You can just put sum=0 in your function and that will work.
In fact, you are doing so in your code2. You innitialized sum as x+y
the issue is because the local and global variable are of same name . so the function will give preference to local variable first . since the local variable is not assigned it gives the error local variable is not assigned.
we can solve this issue by following ways:
1. use global keyword in the function
2. keep names different.
3. use function globals()
thanks

Python closure confusion

I was playing around with closures in Python and I do not understand why the following does not work and how to make it work:
>>> def make_counter():
... i = 0
... def inner():
... i += 1
... return i
... return inner
...
>>> c = make_counter()
>>> c()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in inner
UnboundLocalError: local variable 'i' referenced before assignment
Could anybody shed some light on it?
Thanks.
In the inner function, the statement
i += 1
can be understood like this
i = i + 1
since you are assigning a value to i in this function, Python thinks that you are creating a new variable scoped to this current function. And then when it executes the right hand side expression, i + 1, it finds that i has not been assigned any value before using it. That is why it is throwing
UnboundLocalError: local variable 'i' referenced before assignment
To fix this, you need to explicitly tell Python that you are not creating a new variable, instead, you are accessing a variable from the outer scope, with nonlocal (Python 3.x) like this
>>> def make_counter():
... i = 0
... def inner():
... nonlocal i
... i += 1
... return i
... return inner
...
>>>
>>> make_counter()()
1
Note: If you are using Python 2.x, follow any of the methods mentioned in this question

About the running result of the following code (Python, less than 10 lines) [duplicate]

This question already has answers here:
Local variables in nested functions
(4 answers)
Closed 8 years ago.
Given this piece of code(python)
s = [None]*10
def func():
for i in range(10):
def update():
print i,
s[i] = update
func()
for i in range(10):
s[i]()
why this result is ten 9s, instead of 0,1,2,3,...9 ?
btw, I've also print s[0]~s[9],which are 10 function addresses, and there are different from each other.
You've created a bunch of closures over i, but they are all sharing the same (final) value of i
You need to make a tiny modification like this
>>> s = [None]*10
>>> def func():
... for i in range(10):
... def update(i=i):
... print i,
... s[i] = update
...
>>> func()
>>> for i in range(10):
... s[i]()
...
0 1 2 3 4 5 6 7 8 9
#gnibbler's code will fix yours (so accept his answer if anyone's). As for why it is printing all 9's, look at your update function. You are (again, as #gnibbler mentioned) continuously returning the i that you defined in for i in range(10). Since in your original code you did not call the update method with a function argument, it simply prints the i that was defined in the func scope (a completely different i which will be 9 after the function completes).
To perhaps make it more clear, try changing the i in func to a completely different name - the result will be the same.
What's happening is the same as this:
>>> a = 5
>>> def foo(): print(a)
>>> foo()
5
>>> a = 10
>>> foo()
10
>>> a = 'fred'
>>> foo()
fred
And also the same as this:
>>> def bar(): return b
>>> bar()
Traceback (most recent call last):
File "<pyshell#30>", line 1, in <module>
bar()
File "<pyshell#29>", line 1, in bar
def bar(): return b
NameError: global name 'b' is not defined
>>> b = 3
>>> bar()
3
The variables you used inside a function aren't resolved until the function is called not when it is written. There's some magic, called closures, that means functions defined inside other functions (as your update functions are defined inside func) still have access to all the variables defined in the outer function - but they still don't actually get resolved until the function is called. So, by the time each of your update functions is called, i is 9.
Using default argument values, as in #gnibbler's answer, works because the i that each update looks up will resolve to the argument (which shadows the outer variable). Those won't change, because default argument values are evaluated when the function is defined (which also leads to the mutable defaults bug that a lot of people run into sooner or later).

Can not increment global variable from function in python [duplicate]

This question already has answers here:
Using global variables in a function
(25 answers)
Closed last month.
From this code:
COUNT = 0
def increment():
COUNT = COUNT + 1
increment()
I get the following error:
Traceback (most recent call last):
File "test.py", line 6, in <module>
increment()
File "test.py", line 4, in increment
COUNT = COUNT+1
UnboundLocalError: local variable 'COUNT' referenced before assignment
Why? How can I increment the global variable COUNT from inside the function?
Use a global statement, like so:
COUNT = 0
def increment():
global COUNT
COUNT = COUNT+1
increment()
Global variables can be accessed without using global, but the statement is required in order to change the value of the global variable.
This is because globals don't bleed into the scope of the function. Use the global statement to force this for assignment:
>>> COUNT = 0
>>> def increment():
... global COUNT
... COUNT += 1
...
>>> increment()
>>> print(COUNT)
1
Note that using globals is a really bad idea - it makes code hard to read, and hard to use. Instead, return a value from your function (using return) and use that to do something. If the same data needs to be accessible from a range of functions, consider making a class.
It's also worth noting that CAPITALS is generally reserved for constants, so it's a bad idea to name global variables like this. For normal variables, lowercase_with_underscores is preferred.

Categories