While loop modify global variable - python

I thought loops in python do not change our global variables; however, the code below gives 10 as a result. Can someone explain what is happening here?
source_col_numbers = 9
i = 1
columns = {}
while i <= source_col_numbers:
columns[i] = list(filter(None , source.sheet1.col_values(i)))
i += 1
print(i)

You have declared i as a global variable and then you are using it in the loop.
So, whatever changes you make to i in your program will be applied on that i since it's a global variable.
Global variable means i has a global scope. If you had created i inside a function, it would have a local scope and could not be accessed outside of the function.
So in your case, changes will be made and output will be 10.

Loops do change global variables, so for each iteration of the loop, i will be incremented by 1.

Related

How come a variable in a function is able to reference from outside it's scope?

In this case, the "all_lines" variable is initalised in the context manager, and it is accessible from the function "part_1".
total = 0
with open("advent_input.txt", "r") as txt:
all_lines = []
context_total = 0
for line in txt:
all_lines.append((line.rstrip().split(" ")))
def part_1():
# total = 0
for line in all_lines:
if line[0] == "A":
if line[1] == "Y":
total += 8
elif line[1] == "X":
context_total += 4
However, "context_total", which is also initalised in the context manager, does not work in the function "part_1". And "total" from the global scope does not work either. How come "all_lines" works?
Python does not have general block scope, so anything assigned within the with will be accessible outside of the block.
context_total is different though since you're reassigning it within the function. If you assign within a function, the variable will be treated as a local unless you use global to specify otherwise. That's problematic here though since += necessarily must refer to an existing variable (or else what are you adding to?), but there is no local variable with that name.
Add global context_total to use it within the function, or pass it in as an argument if you don't need the reassigned value externally.
It works because inside the function, the all_lines variable is referenced but not assigned. The other two variables are assigned.
If a variable is assigned inside a function, then that variable is treated as local throughout the function, even if there is a global variable of the same name.

How to change variables in Python functions without using 'global'

I have defined some global parameters in Python (that should also be accesible from other files) and I would like to change them inside the class in which they are defined. I read quite often that one way of doing this is to use 'global' when defining the variables inside the function. However, I also read quite often that 'global' should be avoided basically as it is not good style. Now my question is what other opportunities do I have to change my variables? When just passing them to the function as arguments (this was also one suggestion) their values remain the same.
So here is my code:
from random import random
numberOfBuildings = 10
numberOfVehicles = 10
useMonteCarloMethodForScenarioCreation = True
def monteCarloScenarioGeneration(numberOfBuildings, numberOfVehicles):
numberOfBuildings_MonteCarlo = int( numberOfBuildings *random() *2 + 1)
numberOfVehicles_MonteCarlo = int(numberOfVehicles *random() *2 + 1)
if useMonteCarloMethodForScenarioCreation ==True:
numberOfBuildings = numberOfBuildings_MonteCarlo
numberOfVehicles = numberOfVehicles_MonteCarlo
monteCarloScenarioGeneration(numberOfBuildings, numberOfVehicles)
print('numberOfBuildings: ', numberOfBuildings)
print('numberOfVehicles: ', numberOfVehicles)
The value of the global variables numberOfBuildings and numberOfVehicles are not changed when the function monteCarloScenarioGeneration is called. They keep the same values that they have after being initialized (10). How can I change the global variables without using the keyword global? I'd appreciate any comments.
You should just be able to use return to change the variables outside of the function, if I'm reading this right.
As the last line of the function, put
return numberOfBuildings, numberOfVehicles
and then when calling the function
numberOfBuildings, numberOfVehicles = monteCarloScenarioGeneration(numberOfBuildings, numberOfVehicles)

The rule of thumb as to when we should use a global variable in a function

When I code games with functions, I often get confused as to which variable to global. I've heard that globalizing variables isn't a very practice, so I try to minimize the amount by not globalizing any, and only globalize the ones that the error message tells me to. But doing that is quite annoying, and it wastes time. Can someone tell me the rule of thumb as to when we should global a variable in a function, and when it is not necessary? Here is a sample of what I mean (the functions):
import turtle
from random import randint as rd
from time import sleep
delay = 0.1
wn = turtle.Screen()
wn.setup(400,400)
wn.tracer(0)
player = turtle.Turtle('square')
player.penup()
player.goto(0,-170)
rock = turtle.Turtle('circle')
rock.shapesize(0.5,0.5)
rock.penup()
rock.goto(rd(-190,190),200)
rocks = [rock]
pen = turtle.Turtle(visible=False)
pen.penup()
pen.goto(0,150)
def go_left(): # No globalizing here
if player.xcor() >= -170:
player.setx(player.xcor()-10)
def go_right(): # No globalizing here
if player.xcor() <= 170:
player.setx(player.xcor()+10)
def move_rocks(): # No globalizing here
for rock in rocks:
rock.sety(rock.ycor()-rd(0,2))
def loop_rocks():
global count # rocks not globalized here
for rock in rocks:
if rock.ycor() < -200:
count += 1
rock.goto(rd(-190,190),200)
def add_rocks():
global count # rocks not globalized here
if count == len(rocks) and len(rocks) <= 15:
rock = turtle.Turtle('circle')
rock.shapesize(0.5,0.5)
rock.penup()
rock.goto(rd(-190,190),200)
rocks.append(rock)
count = 0
def write_score():
global time,score,high_score # pen not globalized here
time += 1
if time == 500:
score += 1
time = 0
if score > high_score:
high_score = score
pen.clear()
pen.write(f'Score: {score} High Score: {high_score}',align='center',font=('Arial',10,'bold'))
def hit(): # No globalizing here
for rock in rocks:
if player.distance(rock) < 15:
return True
def die():
global score,rocks # player not globalized here
sleep(1)
for rock in rocks:
rock.goto(300,300)
rocks = rocks[:1]
rocks[0].goto(rd(-190,190),200)
player.goto(0,-170)
score = 0
wn.listen()
wn.onkeypress(go_left,'Left')
wn.onkeypress(go_right,'Right')
score = 0
high_score = 0
count = 0
time = 0
while True:
if hit():
die()
move_rocks()
loop_rocks()
add_rocks()
write_score()
wn.update()
Style rules are not language rules. I.e. you shouldn't use eval(), but there it is, in the language.
tell me the rule of thumb as to when we should global a variable in a
function, and when it is not necessary?
The rules for when, and when not, to use global are simple, but even tutorials on the web get it wrong.
The global keyword should not be used to create a global
variable.
(Yes, that's partly a style rule.) When you define a top level variable outside a function, Python makes it global. (You don't use the global keyword for this.) When you assign to a variable inside a function, Python assumes it is local to the function. You only need the global keyword when you want change that later assumption so you can reassign (=) a global variable from within a function. You don't need the global declaration to examine a global variable. You don't need it to invoke a method on a global variable that might change its internal state or content:
You only need the global keyword when you want to reassign (=) a
global variable within a function.
The global declaration is used in any function where a global variable is reassigned. It is is placed ahead of the first reference to the variable, access or assignment. For simplicity, and style, global statements are put at the beginning of the function.
A statement like, "You should never use global variables", is a style rule and true of most programming languages -- apply it if/when you can. And if you absolutely can't, don't feel bad about it, just:
Comment all globals you do use properly.
Global constants are less an issue:
If global constants are truly constant, they never need the global
keyword.
#juanpa.arrivillaga's example of go_left() taking the additional values as parameters instead of global variables, fails to take into account that go_left() is a callback and that the turtle event assignment functions don't provide for additional parameters. (They should, but they don't.) We can get around this using a lambda expression (or partial function from functools), but when used this way, lambda isn't particularly great style either, IMHO.
#martineau's suggestion of "making them attributes of a class that the class' methods can access" (aka class variables) is fine, but what is left unsaid is that it means subclassing Turtle or wrapping a turtle instance with another class.
My personal issue with mutable globals is that they are problematic in a multi-threaded world.
Although it is not an answer, I just wanted to point out one more thing to look out for when shadowing names from outer scopes / global variables. cdlane writes in their answer that
You don't need the global declaration to examine a global variable.
I think it goes even further than that, because you cannot use the global keyword that way, as it is a declaration. As cdlane already said, it is used to declare variables in a local scope (such as a function or class) to be of global scope, such that you can assign new values to these variables from a local scope. You can even use the gobal keyword to declare new global variables from a local scope, although again, as cdlane pointed out, this is not a good idea. Here is some code highlighting these behaviours:
a = c = 1 # define global variables 'a' and 'b' and assign both the
# value 1.
class Local:
def __init__(self):
print(a) # if you only want to examine the global variable 'a',
# you don't need any keywords
self.declare_variables()
def declare_variables(self):
global a, b # declare 'a' and 'b' as global variables, such that any
# assignment statements in this scope refer to the global variables
a = 2 # reassign a new value to the already existing global
# variable 'a'.
b = 3 # assign a value to the previously undeclared global variable
# 'b'. you should avoid this.
c = 4 # this does not affect the global variable 'c', since the
# variable 'c' in this scope is assumed to be local by default.
local = Local()
print(a, b, c) # the vaules of the gobal variables 'a' and 'b' have changed,
# while 'c' remains unaffected.
So far nothing really new. However, when you are shadowing the names from global variables, but are still accessing the global variables elsewhere in the same scope, this becomes a problem.
If you declare a variable shadowing the name of a global variable before you try to access that global variable, all references to that variable name following that declaration will refer to the local variable. I think this might be the worse case, since this could go undetected and not produce any errors, but return wrong results.
If you try to declare a new local variable, or use the global keyword with the same variable name after you have already referenced that variable name in the same scope, it will result in an UnboundLocalError or SyntaxError, respectively.
def reference_global_before_local_declaration():
print(a) # first reference the global variable 'a'. this statement would
# work on its own if 'a' wouldn't be redeclared to be a local variable
# later on.
a = 5 # redeclare 'a' to be a local variable and assign it the value 5.
reference_global_before_local_declaration()
def reference_global_before_global_declaration():
print(a) # first reference the global variable 'a'. this statement would
# work on its own if 'a' wouldn't be declared to be a global variable
# again later on.
global a # declare 'a' to be a global variable again.
reference_global_before_global_declaration()
def reference_global_after_local_declaration():
a = 'text' # redeclare 'a' to be a local variable of type string and
# assign it the value 'text'.
b = a + 1 # here, 'a' was supposed to reference the global variable
# 'a', but is now referencing the local variable 'a' instead, due to 'a'
# being declared in the same scope and shadowing the name of the gobal
# variable 'a'.
reference_global_after_local_declaration()
The only way that I know of to avoid this, is to use the globals() function, although this really defeats all purpose and I wouldn't recommend it. I would however recommend to read PEP 3104 - Access to Names in Outer Scopes, which discusses these kinds of problems and presents a solution, which was ultimately never implemented though.
def reference_global_before_local_declaration():
print(globals()['a'])
a = 5
reference_global_before_local_declaration()
def reference_global_before_global_declaration():
print(globals()['a'])
global a
reference_global_before_global_declaration()
def reference_global_after_local_declaration():
a = 'text'
b = globals()['a'] + 1
reference_global_after_local_declaration()

Python global keyword [duplicate]

This question already has answers here:
Is it possible to modify a variable in python that is in an outer (enclosing), but not global, scope?
(9 answers)
Closed 5 months ago.
I am confused with the global keyword behavior in below code snippet, I was expecting 30, 30, 30 in all 3 prints.
def outer_function():
#global a ###commented intentionally
a = 20
def inner_function():
global a
a = 30
print('a =',a)
inner_function()
print('a =',a)
a = 10
outer_function()
print('a =',a)
#Output:
#30
#20 #Expecting 30 here
#30
All the confusion coming from "global a" after outer function definition. As my understanding at this point of time is " All the reference and assignment to variable become globally reflected on declaration of global keyword on that variable". If I am uncommenting that first global statement I am getting expected output 30,30,30.
Why global declaration inside inner_function and value change does not reflect on 2nd print i:e to outer_function(or outer scope), whereas got reflected in global namespace.
A common acronym to be familiar with is LEGB:
Local
Enclosed
Global
Built-in
This is the order in which Python will search the namespaces to find variable assignments.
Local
The local namespace is everything that happens within the current code block. Function definitions contain local variables that are the first thing that is found when Python looks for a variable reference. Here, Python will look in the local scope of foo first, find x with the assignment of 2 and print that. All of this happens despite x also being defined in the global namespace.
x = 1
def foo():
x = 2
print(x)
foo()
# prints:
2
When Python compiles a function, it decides whether each of the variables within the definition code block are local or global variables. Why is this important? Let's take a look at the same definition of foo, but flip the two lines inside of it. The result can be surprising
x = 1
def foo():
print(x)
x = 2
foo()
# raises:
UnboundLocalError: local variable 'x' referenced before assignment
This error occurs because Python compiles x as a local variable within foo due to the assignment of x = 2.
What you need to remember is that local variables can only access what is inside of their own scope.
Enclosed
When defining a multi-layered function, variables that are not compiled as local will search for their values in the next highest namespace. Here is a simple example.
x = 0
def outer_0():
x = 1
def outer_1():
def inner():
print(x)
inner()
outer_1()
outer_0()
# print:
1
When inner() is compiled, Python sets x as a global variable, meaning it will try to access other assignments of x outside of the local scope. The order in which Python searches for a value of x in moving upward through the enclosing namespaces. x is not contained in the namespace of outer_1, so it checks outer_0, finds a values and uses that assignment for the x within inner.
x --> inner --> outer_1 --> outer_0 [ --> global, not reached in this example]
You can force a variable to not be local using the keywords nonlocal and global (note: nonlocal is only available in Python 3). These are directives to the compiler about the variable scope.
nonlocal
Using the nonlocal keyword tells python to assign the variable to first instance found as it moves upward through the namespaces. Any changes made to the variable will be made in the variable's original namespace as well. In the example below, when 2 is assigned x, it is setting the value of x in the scope of outer_0 as well.
x = 0
def outer_0():
x = 1
def outer_1():
def inner():
nonlocal x
print('inner :', x)
x = 2
inner()
outer_1()
print('outer_0:', x)
outer_0()
# prints:
inner : 1
outer_0: 2
Global
The global namespace is the highest level namespace that you program is running in. It is also the highest enclosing namespace for all function definitions. In general it is not good practice to pass values in and out of variables in the global namespace as unexpected side effects can occur.
global
Using the global keyword is similar to non-local, but instead of moving upward through the namespace layers, it only searches in the global namespace for the variable reference. Using the same example from above, but in this case declaring global x tells Python to use the assignment of x in the global namespace. Here the global namespace has x = 0:
x = 0
def outer_0():
x = 1
def outer_1():
def inner():
global x
print('inner :', x)
inner()
outer_1()
outer_0()
# prints:
0
Similarly, if a variable is not yet defined in the global namespace, it will raise an error.
def foo():
z = 1
def bar():
global z
print(z)
bar()
foo()
# raises:
NameError: name 'z' is not defined
Built-in
Last of all, Python will check for built-in keywords. Native Python functions such as list and int are the final reference Python checks for AFTER checking for variables. You can overload native Python functions (but please don't do this, it is a bad idea).
Here is an example of something you SHOULD NOT DO. In dumb we overload the the native Python list function by assigning it to 0 in the scope of dumb. In the even_dumber, when we try to split the string into a list of letters using list, Python will find the reference to list in the enclosing namespace of dumb and try to use that, raising an error.
def dumb():
list = 0
def even_dumber():
x = list('abc')
print(x)
even_dumber()
dumb()
# raises:
TypeError: 'int' object is not callable
You can get back the original behavior by referencing the global definition of list using:
def dumb():
list = [1]
def even_dumber():
global list
x = list('abc')
print(x)
even_dumber()
dumb()
# returns:
['a', 'b', 'c']
But again, DO NOT DO THIS, it is bad coding practice.
I hope this helps bring to light some of how the namespaces work in Python. If you want more information, chapter 7 of Fluent Python by Luciano Ramalho has a wonderful in-depth walkthrough of namespaces and closures in Python.
From the documentation:
The global statement is a declaration which holds for the entire
current code block. It means that the listed identifiers are to be
interpreted as globals.
Note it only applies to current code block. So the global in inner_function only applies within inner_function. Outside of it, the identifier is not global.
Note how “identifier” is not the same as “variable”. So what it tells the interpreter is “when I use identifier a within this code block, do not apply normal scope resolution, I actually mean the module-level variable, ”.
Just uncomment your global command in the outer_function, otherwise you're declaring a local variable with value 20, changing a global variable then printing that same local variable.
It's not a good idea use global variabilities. If you want only reset the value of a variable, you just use this lines:
def outer_function():
a = 20
def inner_function():
a = 30
print('a =',a)
return a
a = inner_function()
print('a =',a)
return a
a = 10
a = outer_function()
print('a =',a)

Correct Use Of Global Variables In Python 3

Which is the correct use of global variables in Python 3?:
1) Stating global VAR_NAME once in the core script (not within a function) and then simply referring to the variable as VAR_NAME everywhere else
2) Stating global VAR_NAME once within every function that uses the global variable and then simply referring to the variable as VAR_NAME for the rest of the function and within the core script itself
In the first case the global keyword is pointless, so that is not correct. Defining a variable on the module level makes it a global variable, you don't need the global keyword.
The second example is correct usage.
However, the most common usage for global variables are without using the global keyword anywhere. The global keyword is needed only if you want to reassign the global variables in the function/method.
You need to use the global keyword in a function if you use the global variable in a way that would otherwise be interpreted as an assignment to a local variable. Without the global keyword, you will create a local variable that hides the global in the scope of the function.
Here are a few examples:
global_var = 1
def example1():
# global keyword is not needed, local_var will be set to 1.
local_var = global_var
def example2():
# global keyword is needed, if you want to set global_var,
# otherwise you will create a local variable.
global_var = 2
def example3():
# Without using the global keyword, this is an error.
# It's an attempt to reference a local variable that has not been declared.
global_var += 1
"in a way that would otherwise be interpreted as an assignment to a local variable" --- yes, but here is a subtle detail:
------------------- error: local variable 'c' referenced before assignment
def work():
c += 3
c = 0
work()
print(c)
------------------- error: local variable 'c' referenced before assignment
c = 0
def work():
c += 3
work()
print(c)
------------------- prints [3]
def work():
c.append(3)
c = []
work()
print(c)
------------------- prints [3]
c = []
def work():
c.append(3)
work()
print(c)
The main difference between the first two cases and the next two cases in the above answer would have to be the fact that the list is mutable. For cases like a = 1 a pointer points to the location where 1 is and when you say a = 2 the pointer shifts.
For the case of mutable objects a memory location is allotted and when methods like append are used changes occur to the memory location itself and so the value the mutable references is changed globally.
Now the big question is as to how the function knows the variable we are modifying is a global one or local one because it seems we can modify the global variable if its mutable and we cannot if its non mutable (The function also does not recognize this as the global variable)

Categories