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

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.

Related

Understanding scope of a variable defined in global scope in python [duplicate]

This question already has answers here:
Using global variables in a function
(25 answers)
UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)
(14 answers)
Closed 2 years ago.
num = 0
def func():
print(num)
func()
The above function is supposed to print the value held by variable num and it works. By this, i would assume that func has access of num. But when i try to change the value of num inside the function, it gives me an error. UnboundLocalError: local variable 'num' referenced before assignment
num = 0
def func():
print(num)
num += 1
func()
Why is this happening?
The num variable isn't in the function's local scope, so you can't modify it inside the function since the variable contains an immutable data type (int).
You can take advantage of global keyword or define the variable inside the function.
num = 0
def func():
global num
print(num)
num += 1
func()

Why does global keyword required to access variable defined in outer scope?

Another question does not explain why I can't change variable time_verf without using 'global' in the example (2) but still can do it to the list in the example (4).
On the resource I found that I can not change global variable from within a function, which is clearly illustrated by these examples:
from datetime import datetime, timedelta
time_verf = datetime.now()
I think I understand why the following is working (1):
def check_global():
global time_verf
clean_list = time_verf + timedelta(hours=12) # время очистки листа
if clean_list < datetime.now():
list_verf.clear()
time_verf = datetime.now()
print('ok')
>> check_global()
<< ok
Next it throws exception when I comment out line with global keyword (2):
def check_global():
# global time_verf
clean_list = time_verf + timedelta(hours=12) # время очистки листа
if clean_list < datetime.now():
list_verf.clear()
time_verf = datetime.now()
print('ok')
>> check_global()
<< Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 3, in check_global
UnboundLocalError: local variable 'time_verf' referenced before assignment
And then again can be again referenced without 'global' when line with assignment commented out(3):
def check_global():
# global time_verf
clean_list = time_verf + timedelta(hours=12) # время очистки листа
if clean_list < datetime.now():
list_verf.clear()
# time_verf = datetime.now()
print('ok')
>> check_global()
<< ok
But why am I allowed to update list defined in the outer scope without using global (4)?
list = []
def check_global_list():
list.append('check')
>> check_global_list()
>> list
<< ['check']
When you comment out the global time_verf statement in line 2,
1: def check_global():
2: # global time_verf
3: clean_list = time_verf + timedelta(hours=12) # время очистки листа
4: if clean_list < datetime.now():
5: list_verf.clear()
6: time_verf = datetime.now()
line 6 assigns a value to a local variable time_verf. It is local because assigning it creates it as a local variable. You get an error on line 3 because it refers to the local variable that your code creates in line 6. If you did not have that assignment then time_verf would be global by default.
But whether a variable is global or not does not depend on the order of execution. You appear to expect that because line 3 on its own would make time_verf global by default, then it becomes global and remains global in line 6. But that isn't the way local variables work. The presence of line 6 changes the meaning (and correctness) of line 3. The interpreter examines the entire scope of your function and creates local variables for any names that the code assigns values to. So because of line 6, time_verf is local, even if line 3 on its own would make it global.
There are very good reasons for this behaviour. Suppose line 3 were enclosed in an if-test. Then, according to the behaviour you seem to expect, the variable would be global if the if-test were true, but local if the if-test were false.
The resource you found states "If we need to assign a new value to a global variable then we can do that by declaring the variable as global.", the keyword being "assign". You can access global variables, call methods on them, mutate them without declaring them as global.
It's when you need to assign to them that you need to declare them as global.
Edit: I agree with Roel Schroeven that the core issue here is assignment!
Nevertheless, BoarGules gave a good answer regarding variable lifetime imho. And in addition I think an important point to notice here is mutability vs. immutability. This especially refers to (4) of the question. While the following works fine
a = 2.72 # global scope, defined BEFORE the function
def modify():
b = a + 3.14 # no assignmnet made to a (but to b in this case)
return b # scope of b is local -> 'return' needed to make it available in the outer scope
In [106]: modify()
Out[106]: 5.86
this fails:
a = 2.72
def modify(): # assignment!
a += 3.14 # you would need 'global a' before this to make it work
return a
In [108]: modify()
UnboundLocalError: local variable 'a' referenced before assignment
While a can be called inside modify(), it cannot be modified since it is type float and thus an immutable object.
On the other hand if you do the same with a mutable object like a list, you get
a = [2.72]
def modify():
a[0] = 3.14 # change the reference to another value...
# no return needed
In [110]: modify()
In [110]: a
Out[110]: [3.14]
It doesn't fail AND a changed, even outside the scope of the function! It will fail again if you call a previously undefined variable in the function. Note that a[0] = 3.14 is not an assignment of a to some value but changes a reference stored in a to another value. This is very important if you have multiple functions in a script and pass things around.
For furter reading, there are good resources on the topic out there, e.g. this as a starter and maybe also on the python data model in the docs.

Strange Scoping in Nested Functions [duplicate]

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()

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

How to Manipulate Variable Value inside a Function When The Variable was Declared Outside the Function?

I would like to increase the value of variable count by 1, but only when the function printcount is called in the CODE below.
global count
count = 0
def PrintCount():
count += 1
print count
PrintCount()
When I run this code I get the following error:
Traceback (most recent call last):
File "C:\Users\Cross\Desktop\Code.py", line 8, in <module>
PrintCount()
File "C:\Users\Cross\Desktop\Code.py", line 5, in PrintCount
count += 1
UnboundLocalError: local variable 'count' referenced before assignment
I would like to know why this is happening and how to fix it.
Thank You.
Use global keyword inside the function to access (especially modify) the global variable count:
def PrintCount():
global count # <----
count += 1
print count
Declaring global outside the function has no effect.
In python, you can read the global variables but you cannot change them without global keyword.
def PrintCount():
global count
count += 1
print count
But the best way to do this would be to pass the count as a parameter to the function, do processing, return the value like this. Try to avoid global as much as possible.
def increment(count):
print count + 1
return count + 1
count = increment(count)
count = 0
def PrintCount():
global count
count += 1
print count
Print()

Categories