Wieso kommt ein Fehler obwohl die Variable global ist?

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()
Alex950130 
Fragesteller
 16.04.2023, 14:01

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?

0
mihisu  16.04.2023, 14:36
@Alex950130

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.

0