-3

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?

zsjng
  • 3
  • 2
  • Does this answer your question? [Assigning to variable from parent function: "Local variable referenced before assignment"](https://stackoverflow.com/questions/8934772/assigning-to-variable-from-parent-function-local-variable-referenced-before-as) – matszwecja Jul 06 '22 at 11:04
  • @matszwecja pay closer attention to the question, in this case his variables are assigned before the calls to methods, so in vanilla python it would work perfectly fine, the difference between the two code comes from subtelty of tkinter, not simple coding mistake. – jeekiii Jul 06 '22 at 11:19
  • @jeekiii idk how you define "vanilla Python" but that's not true. If you had removed `count += 1` from the first example the code would run just fine. – matszwecja Jul 06 '22 at 11:33
  • @matszwecja Sorry that's true, but the second code wouldn't run then. He also defined var after the select yet it runs because of tkinter subtelty. – jeekiii Jul 06 '22 at 11:37
  • Again, nothing to do with tkinter. I'm writing a (hopefully) exhaustive answer to show you both what is going on. – matszwecja Jul 06 '22 at 11:38
  • Also I don't know much about tkinter, but I would assume putting count = 0 before the click_me function would not be enough to make it run – jeekiii Jul 06 '22 at 11:38

1 Answers1

0

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.

matszwecja
  • 6,357
  • 2
  • 10
  • 17
  • so when put `var=var`, python will find right side var in select(). and can not find it, so that geit `UnboundLocalError` error right? I understant it. thanks a lot. Is there any wat to count the button press time without `global count`? – zsjng Jul 06 '22 at 12:33
  • Yes, because of `var = ...` var is treated as a local variable by Python. So when it tries to get the value (`= var`) it raises an error because such a variable was not yet assigned to in local scope. – matszwecja Jul 06 '22 at 12:35