Variable referenced before assignment - Python - python

I am getting the error...
a = a + b
UnboundLocalError: local variable 'a' referenced before assignment
I don't understand why the error occurs if I have assigned the two variables a and b at the start.
from tkinter import *
a = 10
b = 12
def stopProg(e):
root.destroy()
def addNumbers(e):
a = a + b
label1.configure(text= str(a))
root=Tk()
button1=Button(root,text="Exit")
button1.pack()
button1.bind('<Button-1>',stopProg)
button2=Button(root,text="Add numbers")
button2.pack()
button2.bind('<Button-1>',addNumbers)
label1=Label(root,text="Amount")
label1.pack()
root.mainloop()

Whenever you modify a global variable inside a function, you need to first declare that variable as being global.
So, you need to do this for the global variable a since you modify it inside addNumbers:
def addNumbers(e):
global a
# This is the same as: a = a + b
a += b
# You don't need str here
label1.configure(text=a)
Here is a reference on the global keyword.
Also, I would like to point out that your code can be improved if you use the command option of Button:
from tkinter import *
a = 10
b = 12
def stopProg():
root.destroy()
def addNumbers():
global a
a += b
label1.configure(text=a)
root=Tk()
button1=Button(root, text="Exit", command=stopProg)
button1.pack()
button2=Button(root, text="Add numbers", command=addNumbers)
button2.pack()
label1=Label(root, text="Amount")
label1.pack()
root.mainloop()
There is never a good reason to use binding in place of the command option.

Here is your answer :
This is because when you make an assignment to a variable in a scope, that variable becomes local to that scope and shadows any similarly named variable in the outer scope.
Please read this : http://docs.python.org/2/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value

You are modifying a global variable. By default, you can read values from global variables, without declaring them as global, but to modify them you need to declare them as global like this
global a
a = a + b

Related

why tkinter variable can be used in function with out incoming and regular variable need incoming

today I am studying tkinter and meet something strange, can anyone help?
Here is my first code:
from tkinter import *
def click_me():
count += 1
print(f'You press {count} times button!')
root = Tk()
count = 0
Button(root, text='click me', command=click_me).pack()
root.mainloop()
I run this code get info:
local variable 'count' referenced before assignment
I can understand it because when I learn python, they told me I need use global or click_me(count) to do this job.
Here is my second code:
from tkinter import *
def select():
print(f'Checkbutton value is {str(var.get())}')
root = Tk()
var = IntVar() # return bool value into 1 or 0.
Checkbutton(root, text='click me', variable=var, command=select).pack()
root.mainloop()
I can run second code without any error. So I think count and var both are variable, the differece are one is regular variable and another are tkinker varialbe, is that reason?
In Python, by default, you can only assign to variables in the innermost scope. When you do count += 1 (which is pretty much same as count = count + 1) you assign to count, so Python treats it as a local variable. Because of that, when you try to calculate value of count + 1 you get UnboundLocalError.
Consider the following:
from tkinter import *
def click_me():
print(f'You press {count + 1} times button!')
root = Tk()
count = 0
Button(root, text='click me', command=click_me).pack()
root.mainloop()
This code works, because you only access the value of count, and do not assign to it inside the function. So, when it is not found in the local scope, Python searches for it in the enclosing scopes.
Now, to the example with var
from tkinter import *
def select():
print(f'Checkbutton value is {str(var.get())}')
root = Tk()
var = IntVar() # return bool value into 1 or 0.
Checkbutton(root, text='click me', variable=var, command=select).pack()
root.mainloop()
Here, you also do not assign to var, so it does not get marked as local. Now, let's add seemingly pointless line of code: var = var
def select():
var = var
print(f'Checkbutton value is {str(var.get())}')
This gives us exactly same error as with count - because of assignment to var, it is treated as a local variable and thus you get an error when trying to access its value.

Is there a way to change a global value from inside a function?

I am currently working an a snake game, but I first want a settings window to show up.i used tkinter for this. In smaller projekts I just wrote all of the code into the pressButton function, but I want to have non spagetti code now, so im not going with that. The problem is, that I have no idea how to get the entered values in the entry brackets into my main code, as global variables, out of the pressButton function and the settingsWin function. The problem is that I use the function as a command for the Button, so I cannt use "return". Can you change global variables in the main code direcktly from inside of a function? If yes how? Or is there another way to solve this?
My Code:
def settingsWin():
def pressButton():
len = entryLen.get()
wid = entryWid.get()
speed = entrySpeed.get()
print(len+wid+speed)
SettingsWin.destroy()
return len
SettingsWin = Tk()
SettingsWin.geometry("600x600")
SettingsWin.title("Settings")
label1 = Label(SettingsWin, text="playing field [tiles]")
label1.pack()
entryLen = Entry(SettingsWin, bd=2, width=20)
entryLen.pack()
label2 = Label(SettingsWin, text="X")
label2.pack()
entryWid = Entry(SettingsWin, bd=2, width=20)
entryWid.pack()
labelblanc = Label(SettingsWin, text="")
labelblanc.pack()
label3 = Label(SettingsWin, text="Speed [ms per tick]")
label3.pack()
entrySpeed = Entry(SettingsWin, bd=2, width="20")
entrySpeed.pack()
okButton = Button(SettingsWin, text="OK", command=pressButton)
okButton.pack()
SettingsWin.mainloop()
len = "len"
wid = "wid"
speed = "speed"
It is often indicative of code smell to require that a function alter variables at scopes outside the function (except possibly in the case of closures, which are quite useful), it is possible to do so using the global keyword:
greeting = "Hello world!"
def greet():
global greeting
greeting = "Goodbye world!"
print(greeting)
greet()
print(greeting)
By declaring the variable greeting to be of global scope, altering the variable within the function definition allows the function to affect the global variable.
If you are working within nested subs, the nonlocal keyword will provide access within the inner sub, to the variable in the outer sub. It works similar to global, except that it is for broader lexical scope, not global scope.

Python tkinter RadioButton callback function

This comes from a button that when pressed generates a radiobutton. I am not able to access to the choice made with radiobutton. Everything works fine, but the output of selected function is zero. I try using both local and global var but the result is the same.
def callback_st(): # RadioButton select technology
var = IntVar()
m=0
for m in range(len(un_tech)):
Radiobutton(radio_frame, text=un_tech[m], value=m, variable=var,
command=selected(var)).pack(anchor=W)
def selected(var):
print(var)
This doesn't work. I solved using lambda:
def selected(jst):
global sel_technology
sel_technology=un_tech[jst]
print(sel_technology)
def callback_st(): #RadioButton select technology
var_st = IntVar()
m=0
for m in range(len(un_tech)):
Radiobutton(radio_frame, text=un_tech[m], value=m, variable=var_st,
command = lambda jst=m: selected(jst)).pack(anchor=W)
This works as i want, but it isn't the solution that i want and i think is not the correct way. So, somebody can help me to find the right way?
In your first try, you call selected immediately, when var has a value of 0. You avoided this with the lambda expression, but you are correct that this is an awkward workaround for the original mistake. Make var global and have selected access it as a global. Modifying your first code:
var = IntVar()
def selected():
print(var.get())
def callback_st():
...
...command=selected...
If you were defining a class and methods, var would be an instance attribute instead of global.

Return statement not working python 3

The idea of this code is, the user presses the first button and enters what they want, then they press the second button and it prints it out. Can someone please tell me why my return statement is not working? It says that 'variable' is not defined. Thanks in advance for taking the time to read my question.
from tkinter import*
def fun():
variable = input('Enter Here:')
return variable
def fun_2():
print(variable)
window = Tk()
button = Button(text = 'Button', command = fun )
button2 = Button(text = 'Button2', command = fun_2 )
button.pack()
button2.pack()
window.mainloop()
In python when you create a variable inside of a function, it is only defined within that function. Therefore other functions will not be able to see it.
In this case, you will probably want some shared state within an object. Something like:
class MyClass:
def fun(self):
self.variable = input('Enter Here:')
def fun_2(self):
print(self.variable)
mc = MyClass()
window = Tk()
button = Button(text = 'Button', command = mc.fun )
button2 = Button(text = 'Button2', command = mc.fun_2 )
button.pack()
button2.pack()
fun() may return a value, but Tkinter buttons don't do anything with that return value.
Note that I used the phrase return a value, not return a variable. The return statement passes back the value of an expression, not the variable variable here. As such, the variable variable is not made into a global that other functions then can access.
Here, you can make variable a global, and tell fun to set that global:
variable = 'No value set just yet'
def fun():
global variable
variable = input('Enter Here:')
Since you did use any assignment in fun2, variable there is already looked up as a global, and it'll now successfully print the value of variable since it now can find that name.
The problem is in in fun2(). It does not get variable as an input parameter.
def fun_2(variable):
print(variable)
But note that you have to call fun_2 now with the appropriate argument. Also, as the function stands right now, there is little point in having the function if you just do a print inside of it.
Take away message: variable is not global in Python, and as such you must pass it to each function that wants to use it.

Global name v is not defined (but it actually is)? tkinter/python

I keep getting this error "global name v is not defined." I know this has most likely been heavily documented, however none of the other threads were very relavant to my GUI situation. Anyway, here we go:
v_amount= 5000
def set_v_to_something_else():
global v
v_amount=v_amount-1000
v.set(v_amount)
v = StringVar()
v.set(str(v_amount))
#create button that will allow v label to be set to something else
vbutton = Button(root, text = "change v", command = set_v_to_something_else).pack()
vlabel = Label(root, textvariable=v).pack()
Once again, it says that v is not defined, even though i set it equal to StringVar()
Thanks in advance
Perhaps you are getting the error
global name v_amount is not defined
That would be because, in this code,
v_amount= 5000
def set_v_to_something_else():
global v
v_amount=v_amount-1000
v.set(v_amount)
when Python parses the function set_v_to_something_else, it marks v_amount as a local variable because it appears on the left-hand side of an assignment:
v_amount=v_amount-1000
Later, when the function is called, since Python regards v_amount as a local variable, it tries to evaluate the right-hand side of the assignment statement first and finds v_amount is not defined. (Remember, it is looking for it in the local namespace, not the global namespace.)
The fix is to add global v_amount inside the function:
def set_v_to_something_else():
global v_amount
v_amount = v_amount-1000
v.set(v_amount)
You can also remove
global v
because you are not assigning a new value to v. v.set is merely calling a method of v.
v_amount= 5000
# you need to define variable 'v' here,
# before you define function that uses it
def set_v_to_something_else():
global v
v_amount=v_amount-1000
v.set(v_amount)
v = StringVar()
v.set(str(v_amount))
#create button that will allow v label to be set to something else
vbutton = Button(root, text = "change v", command = set_v_to_something_else).pack()
vlabel = Label(root, textvariable=v).pack()

Categories