Python Global Variables - Not Defined? - python

I'm running into an issue where a global variable isn't "remembered" after it's modified in 2 different functions. The variable df is supposed to be a data frame, and it doesn't point to anything until the user loads in the right file. This is similar to something I have (using pandas and tkinter):
global df
class World:
def __init__(self, master):
df = None
....
def load(self):
....
df = pd.read_csv(filepath)
def save(self):
....
df = df.append(...)
save() is always called after load(). Thing is, when I call save(), I get the error that "df is not defined." I thought df got its initial assignment in init(), and then got "updated" in load()? What am I doing wrong here?

You have to use global df inside the function that needs to modify the global variable. Otherwise (if writing to it), you are creating a local scoped variable of the same name inside the function and your changes won't be reflected in the global one.
p = "bla"
def func():
print("print from func:", p) # works, readonly access, prints global one
def func1():
try:
print("print from func:", p) # error, python does not know you mean the global one
p = 22 # because function overrides global with local name
except UnboundLocalError as unb:
print(unb)
def func2():
global p
p = "blubb" # modifies the global p
print(p)
func()
func1()
print(p)
func2()
print(p)
Output:
bla # global
print from func: bla # readonly global
local variable 'p' referenced before assignment # same named local var confusion
bla # global
blubb # changed global

for anyone coming here using python3 - try using nonlocal instead of global - a new construct introduced in python3 which allows you to mutate and read global variables in local scope

You have to use the global keyword inside the function rather than outside. All the df that you have defined inside your function are locally scoped. Here is the right way -
df = pd.DataFrame() # No need to use global here
def __init__(self, master):
global df # declare here
df = None
....
def load(self):
global df # declare here
....
df = pd.read_csv(filepath)
def save(self):
global df # declare here
....
df = df.append(...)

Related

Are there cases where global keyword is necessary in python?

I want to know if there are some cases where declaring global keyword is necessary in python.
Yes, there are some cases where global is neccessary.
Have a look at this code, which will work fine:
i = 42 # this is a global var
def f():
print(i)
But what if you would like to edit i (which is a global variable).
If you do this, you get an error:
i = 42 # this is a global var
def f():
i += 1 # this will not work
print(i)
We can only access i. If python compiles the function to bytecode it detects an assignment to a variable and it assumes it is a local variable. But this is not the case here (it is a global variable). Therefore if we also want to modify the global var i we must use the global keyword.
i = 42 # this is a global var
def f():
global i
i += 1 # this will change the global var without error
print(i)
When you have shared resources and want to make changes in global one.
a = 0
def add_five():
global a
a += 5
def remove_two():
global a
a -= 2
add_five() # a = 5
add_five() # a = 10
add_five() # a = 15
remove_two() # a = 13

Why is this variable not defined if it is a global variable?

I create a list and try to append it to another list, but even though it is a global list it still is not defined.
I had the same issue trying to apppend a string to another list, and that had the same error so I tried to make the string a list.
sees if the player hits
def hit_or_stand():
global hit **<-- notice hit is a global variable**
if hitStand == ("hit"):
player_hand()
card = deck()
hit = []
hit.append(card)
now I need to append hit to pHand (player's hand)
def player_hand():
global pHand
deck()
pHand = []
pHand.append(card)
deck()
pHand.append(card)
pHand.append(hit) **<--- "NameError: name 'hit' is not defined"**
pHand = (" and ").join(pHand)
return (pHand)
hit_or_stand()
player_hand()
global hit
This does not declare a variable which is global. It does not create a variable which does not exist. It simply says "if you see this name in this scope, assume it's global". To "declare" a global variable, you need to give it a value.
# At the top-level
hit = "Whatever"
# Or in a function
global hit
hit = "Whatever"
The only time you need a global declaration is if you want to assign to a global variable inside a function, as the name could be interpreted as local otherwise. For more on globals, see this question.
There is a misunderstanding of the global operation in OP's post. The global inside a function tells python to use that global variable name within that scope. It doesn't make a variable into a global variable by itself.
# this is already a global variable because it's on the top level
g = ''
# in this function, the global variable g is used
def example1():
global g
g = 'this is a global variable'
# in this function, a local variable g is used within the function scope
def example2():
g = 'this is a local variable'
# confirm the logic
example1()
print( g ) # prints "this is a global variable"
example2()
print( g ) # still prints "this is a global variable"

How do I pass a variable between functions python

Here are my two functions:
def selectBadge(a):
curItem = SelectBadgeView.focus()
inter_var = SelectBadgeView.item(curItem)
ListValues = inter_var['values']
print(ListValues)
SelectedBadge.set("Selected Badge: "+str(ListValues[0]))
SelectedBadgeStr=str(ListValues[0])
return SelectedBadgeStr
def selectScout(a,SelectedBadgeStr):
print(a)
if SelectedPatrol.get()==("Selected Patrol: Please Select A Patrol"):
tk.messagebox.showerror("ERROR","Please select a Patrol")
return
if SelectedBadge.get()==("Selected Badge: Please Select A Badge"):
tk.messagebox.showerror("ERROR", "Please select a Badge")
return
print(SelectedBadgeStr)
return
I want to pass the variable SelectedBadgeStr from selectBadge() to selectScout().
The variable a is a internal variable used by the tkinter treeview widget.
a = <ButtonRelease event state=Button1 num=1 x=144 y=39>
I have tried:
return SelectedBadgeStr
However this did not work.
The function is called by:
SelectScoutView.bind('<ButtonRelease-1>', selectScout)
Did you declare SelectedBadgeStr as for example an empty string before defining the function selectBadge(a)?
So just declare it like:
SelectedBadgeStr = ''
def selectBadge(a):
curItem = SelectBadgeView.focus()
.
.
.
It should work.
You can also use a shared global variable:
Declare the variable outside of the functions use:
SelectedBadgeStr = None
At the beginning of the functions use:
global SelectedBadgeStr
Whenever you use the variable now within the functions, you access the global variable

I need a delegate class?

I have a problem that sounds like a delegation problem. I have a code like the following:
class foo(object):
def __init__(self,onEvent1="", onEvent2=""):
self.OnEvent1=onEvent1
self.OnEvent1=onEvent2
def aLoop(self):
...
#in case of event1
self.OnEvent1()
...
#in case of event2
self.OnEvent2()
EventType=0
def MyBar1():
print("Event Type1")
EventType=1
def MyBar2():
print("Event Type2")
EventType=2
myFoo=foo(MyBar1,MyBar2)
while True:
myFoo.aLoop()
if (EventType==1):
print ("EventType is 1")
EventType=0
elif (EventType==2):
print ("EventType is 2")
EventType=0
I can see the message of the print() inside the callback functions but not the print() of the messages in the while loop.
The variable EventType doesn't change its value.
What I can do?
The EventType variables in MyBar1 and MyBar2 are local variables. Any variable you bind to is a local, unless explicitly configured otherwise; assignments, function parameters, a function or class definition and names you import are all ways to bind a name.
You need to use a global statement to change this:
def MyBar1():
global EventType
print("Event Type1")
EventType=1
def MyBar2():
global EventType
print("Event Type2")
EventType=2
Note that there is little point in giving your event arguments an empty string as default argument:
def __init__(self,onEvent1="", onEvent2=""):
If they are optional, set them to None and test for that:
def __init__(self, onEvent1=None, onEvent2=None):
self.OnEvent1 = onEvent1
self.OnEvent2 = onEvent2
def aLoop(self):
...
#in case of event1
if self.OnEvent1 is not None:
self.OnEvent1()
...
#in case of event2
if self.OnEvent2 is not None:
self.OnEvent2()
EventType=0
def MyBar1():
global EventType
print("Event Type1")
EventType=1
def MyBar2():
global EventType
print("Event Type2")
EventType=2
The problem is, you need to modify a global variable, but you're creating a local one instead. You can still access the global variable without using global variable. You need this to modify it.

how to append item to a global list from within a procedure

I get a syntax error when i do this:
p = []
def proc(n):
for i in range(0,n):
C = i
global p.append(C)
Just change it to the following:
def proc(n):
for i in range(0,n):
C = i
p.append(C)
The global statement can only be used at the very top of a function, and it is only necessary when you are assigning to the global variable. If you are just modifying a mutable object it does not need to be used.
Here is an example of the correct usage:
n = 0
def set_n(i):
global n
n = i
Without the global statement in the above function this would just create a local variable in the function instead of modifying the value of the global variable.
The problem is you are trying to print list directly instead convert into a string before printing,and as array is a member of class Student, you need to reference it using 'self'.
The following code works:
class Student:
array = []
def addstudent(self,studentName):
print("New Student is added "+studentName)
self.array.append(studentName)
print(str(self.array))
def removeStudent(self,studentName):
print("Before Removing the Students from the list are "+ str(self.array))
self.array.remove(studentName)
print("After Removing the students from the list are "+ str(self.array))
if __name__ == '__main__':
studata = Student()
studata.addstudent("Yogeeswar")
studata.addstudent("Linga Amara")
studata.addstudent("Mahanti")
studata.removeStudent("Yogeeswar")

Categories