Wieso kommt ein Fehler obwohl die Variable global ist?
Hallo.
Ich habe einen Python Code, der mir erstmal ausgeben soll, wie oft ich auf den Button geklickt habe:
from tkinter import *
from time import *
Fenster = Tk()
Fenster.geometry(str(Fenster.winfo_screenwidth())+"x"+str(Fenster.winfo_screenheight()))
Fenster.title("Funktionen")
def Klickschnelligkeit_prüfen():
Test = 0
def vp():
global Test
Test += 1
print(Test, "a")
Button(text = "Hier klicken", command = vp).place(x = Fenster.winfo_screenwidth()/12, y = Fenster.winfo_screenheight()/12)
Button(text = "Klickschnelligkeit prüfen", command = Klickschnelligkeit_prüfen).place(x = Fenster.winfo_screenwidth()/6*5, y = Fenster.winfo_screenheight()/20*4)
mainloop()
Jetzt kommt aber, wenn ich nach dem Klick auf den Button "Klickschnelligkeit prüfen" auf den Button "Hier klicken" drücke, ein Fehler:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.1008.0_x64__qbz5n2kfra8p0\Lib\tkinter\__init__.py", line 1948, in __call__
return self.func(*args)
^^^^^^^^^^^^^^^^
File "e:\Programmieren\Aktuell\Funktionen.py", line 63, in vp
Test += 1
^^^^
NameError: name 'Test' is not defined
Kann mir jemand sagen, wieso?
Danke für eure Hilfe, Alex.
1 Antwort
Du benutzt ab der Stelle „global Test“ eine globale Variable Test. Diese kannst du jedoch bei „Test += 1“ nicht um 1 erhöhen, da sie zu diesem Zeitpunkt noch gar nicht mit irgendeinem Wert initialisiert worden ist.
Die Variable, die du zuvor mit „Test = 0“ in der Umgebung von Klickschnelligkeit_prüfen() definiert hast, ist NICHT gleich der globalen Variable Test, sondern ist nur eine lokale Variable, die innerhalb des Funktionsaufrufs Klickschnelligkeit_prüfen() existiert. Innerhalb der Funktion vp() wird diese durch „Test = 0“ definierte lokale Variable aber wegen „global Test“ von der (nicht initialisierten!) globalen Variable Test überschattet.
Eine mögliche Lösung, bei der man nicht viel am Code ändern muss: Nutze bei „Test = 0“ in Klickschnelligkeit_prüfen() ebenfalls die globale Variable Test.
from tkinter import *
from time import *
Fenster = Tk()
Fenster.geometry(str(Fenster.winfo_screenwidth())+"x"+str(Fenster.winfo_screenheight()))
Fenster.title("Funktionen")
def Klickschnelligkeit_prüfen():
global Test
Test = 0
def vp():
global Test
Test += 1
print(Test, "a")
Button(text = "Hier klicken", command = vp).place(x = Fenster.winfo_screenwidth()/12, y = Fenster.winfo_screenheight()/12)
Button(text = "Klickschnelligkeit prüfen", command = Klickschnelligkeit_prüfen).place(x = Fenster.winfo_screenwidth()/6*5, y = Fenster.winfo_screenheight()/20*4)
mainloop()
Oder evtl. noch besser... Nutze „nonlocal Test“ statt „global Test“.
from tkinter import *
from time import *
Fenster = Tk()
Fenster.geometry(str(Fenster.winfo_screenwidth())+"x"+str(Fenster.winfo_screenheight()))
Fenster.title("Funktionen")
def Klickschnelligkeit_prüfen():
Test = 0
def vp():
nonlocal Test
Test += 1
print(Test, "a")
Button(text = "Hier klicken", command = vp).place(x = Fenster.winfo_screenwidth()/12, y = Fenster.winfo_screenheight()/12)
Button(text = "Klickschnelligkeit prüfen", command = Klickschnelligkeit_prüfen).place(x = Fenster.winfo_screenwidth()/6*5, y = Fenster.winfo_screenheight()/20*4)
mainloop()
Bei der „nonlocal“-Version wird in vp() die „Test“-Variable aus der Umgebung der äußeren Klickschnelligkeit_prüfen()-Funktion verwendet. Die verwendete Test-Variable lebt also nur in der Klickschnelligkeit_prüfen()-Funktion, nicht in der globalen Umgebung.
Bei der „global“-Version hat man dagegen beispielsweise unter Umständen ein Problem, wenn eine andere Funktion ebenfalls die globale Test-Variable verwendet. Dann könnte die globale Test-Variable unerwartete Werte annehmen, wenn da unterschiedliche Funktionen „reinpfuschen“.
Hier mal drei einander ähnliche Beispiele (mit recht unterschiedlichen Ergebnissen) zum Vergleich, um dir die Unterschiede zu veranschaulichen...
Beispiel 0: [Zum Vergleich mit deinem ursprünglichen Code.]
Test = 10 # globale Variable
def a():
Test = 20 # lokale Variable in der a()-Umgebung
def b():
global Test # Variable aus der globalen Umgebung
Test += 1 # Variable aus globaler Umgebung
print(f"Ende b(): Test = {Test}") # globale Variable
b()
b()
print(f"Ende a(): Test = {Test}") # Variable aus a()-Umgebung
a()
print(f"Ende global: Test = {Test}") # globale Variable
Ausgabe zu Beispiel 0:
Ende b(): Test = 11
Ende b(): Test = 12
Ende a(): Test = 20
Ende global: Test = 12
Hier wird in b() die globale Variable, die mit Test = 10 initialisiert worden ist, verändert, statt dass die in a() durch Test = 20 definierte lokale Variable verwendet wird.
Beispiel 1: [Zum Vergleich mit der „global“-Version der Verbesserung.]
Test = 10 # globale Variable
def a():
global Test # globale Variable
Test = 20 # globale Variable
def b():
global Test # globale Variable
Test += 1 # globale Variable
print(f"Ende b(): Test = {Test}") # globale Variable
b()
b()
print(f"Ende a(): Test = {Test}") # globale Variable
a()
print(f"Ende global: Test = {Test}") # globale Variable
Ausgabe zu Beispiel 1:
Ende b(): Test = 21
Ende b(): Test = 22
Ende a(): Test = 22
Ende global: Test = 22
Hier bleibt die globale Variable „Test“ beim ursprünglichen Wert 10, ohne durch die Funktionen a() bzw. b() verändert zu werden. Es wird nur die lokal in der Umgebung des Funktionsaufrufs a() lebende Variable Test verändert.
Beispiel 2: [Zum Vergleich mit der „nonlocal“-Version der Verbesserung.]
Test = 10 # globale Variable
def a():
Test = 20 # lokale Variable in a()-Umgebung
def b():
nonlocal Test # Variable aus a()-Umgebung
Test += 1 # Variable aus a()-Umgebung
print(f"Ende b(): Test = {Test}") # Variable aus a()-Umgebung
b()
b()
print(f"Ende a(): Test = {Test}") # Variable aus a()-Umgebung
a()
print(f"Ende global: Test = {Test}") # globale Variable
Ausgabe zu Beispiel 2:
Ende b(): Test = 21
Ende b(): Test = 22
Ende a(): Test = 22
Ende global: Test = 10
Hier bleibt die globale Variable „Test“ beim ursprünglichen Wert 10, ohne durch die Funktionen a() bzw. b() verändert zu werden. Es wird nur die lokal in der Umgebung des Funktionsaufrufs a() lebende Variable Test verändert.
Danke für deine Antwort, bei mir haben auch beide Möglichkeiten funktioniert. Aber was genau ist der Unterschied zwischen global und nonlocal, dass ich global 2 mal hinschreiben muss aber nonlocal nur 1 mal?