Python Forum

Full Version: not updating
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
:I Wall Wall
import tkinter as tk
window = tk.Tk()

score = 0

def click():
  score += 1
  score_display.config(text=score)

score_display = tk.Label(text=score)
score_display.pack()
button = tk.Button(text='Click me!', command=click)
score_display.pack()

window.mainloop()
When a function assigns a value to a variable, it creates a local variable. score in line 7 is not the same score in line 4. Score in line 7 only exists in the function and gets created each time the function is called. There is no way to accumulate clicks because score keeps getting created and destroyed each time clink is called. In fact, line 7 raises an exception when click() is called. Tkinter hides that from you. You could use “ global score” in click() to fix, but I think a better solution is to make score a IntVar.
Also line 13 score_display.pack() should be button.pack()
import tkinter as tk
window = tk.Tk()
 
score = 0
 
def click():
  global score # <- allows updating varibales on module level
  # if this is missing, it's a UnboundLocalError
  # The use of globals is bad
  score += 1
  score_display.config(text=score)
 
score_display = tk.Label(text=score)
score_display.pack()
button = tk.Button(text='Click me!', command=click)
button.pack() # <-- this was missing
score_display.pack()
 
window.mainloop()
A slightly better version:
import tkinter as tk

 
class Score:
    """
    Simple class to avoid the use of globals
    """
    def __init__(self, score_display):
        self.score = 0
        self.score_display = score_display

    def click(self):
       self.score += 1
       score_display.config(text=self.score)


window = tk.Tk()
score_display = tk.Label(text="0")
score_display.pack()
score = Score(score_display) # <- keep the instance of score_display and score
button = tk.Button(text='Click me!', command=score.click) # <- using the method score to update the score
button.pack() # <-- this was missing
score_display.pack()

tk.Button(window, text="Close", command=window.destroy).pack()

window.mainloop()
You can use also use IntVar from tkinter.
Updated code:
import tkinter as tk

 
class Score:
    """
    Simple class to avoid the use of globals
    """
    def __init__(self, score_variable: tk.IntVar):
        self.score = score_variable

    def click(self):
        self.score.set(self.score.get() + 1)

window = tk.Tk()
score_variable = tk.IntVar(window)
score_display = tk.Label(textvariable=score_variable) # <- the us of textvariable instead of text
# if score_variable changes, the score_display is updated automatically
score_display.pack()
score = Score(score_variable) # <- keep the instance of score_variable
button = tk.Button(text='Click me!', command=score.click) # <- using the method score to update the score
button.pack() # <-- this was missing
score_display.pack()

tk.Button(window, text="Close", command=window.destroy).pack()
tk.IntVar()
window.mainloop()
I would use IntVar in a slightly different way. This code subclasses IntVar to make an IntVar that has a click() method.
import tkinter as tk

class Score(tk.IntVar):
    """Add click() method to IntVar class."""

    def click(self):
        self.set(self.get() + 1)

window = tk.Tk()
score_variable = Score(window)
score_display = tk.Label(textvariable=score_variable)
score_display.pack()
button = tk.Button(text="Click me!", command=score_variable.click)
button.pack()
score_display.pack()
window.mainloop()
But you can also just make a global IntVar and use it like this.
import tkinter as tk


def clicked():
    score.set(score.get() + 1)


window = tk.Tk()
score = tk.IntVar(window, 0)
score_display = tk.Label(textvariable=score)
score_display.pack()
button = tk.Button(text="Click me!", command=clicked)
button.pack()
score_display.pack()
window.mainloop()
In this code the "score" in line 5 is the same "score" as in lines 9 and 10. Because there is not assignment in "clicked()", python does not create any local variables for the function. When clicked() executes it looks for a variable named "score" in the local variables, doesn't find one, and looks for a global variable named "score".

Takeaways:
assignment (=) creates variables in python. When the python code parser encounters an assignment, it creates a variable in the local scope.

global name circumvents the creation of local variables. When a function has "global name" it does not create a local variable with that name.

When a variable is encountered in a function, python first looks for a local variable with that name. If it doesn't find a matching local variable it looks for a matching global variable. If there is not a matching global variable, python looks for the variable in the builtins (built in functions like print, list...). There is an additional scope named "enclosed" that sits between local and global.

 Global variables should be avoided. Because global variables can be seen by everything in the module, changes that affect the use of global variables require a code review of all code in the module.