Globale und Lokale Variablen¶
Python behandelt globale und lokale Variablen in einer eigenwilligen Art. Während in vielen anderen Programmiersprachen Variablen automatisch global sind, wenn man sie nicht explizit als lokal deklariert, ist dies in Python genau anders herum. Die zugrundeliegende Idee besteht darin, dass die Benutzung von globalen Variabeln generell als schlechter Programmierstil betrachtet wird, weil dadurch viele Fehler und Seiteneffekte auftreten können. In den meisten Fällen, in denen man versucht ist, eine globale Variable zu verwenden, kann man den gewünschten Effekt besser mittels eines Funktionsparameters realisieren oder durch die Rückgabe eines Wertes mittels eines return-Wertes. Wie auch in vielen anderen Fällen, wird hier durch das Design von Python ein guter Programmierstil gewissermaßen erzwungen.
Das bedeutet, dass jede Variable, die man innerhalb einer Funktion definiert, automatisch einen lokalen Gültigkeitsbereich hat. Das bedeutet, dass was immer man mit dieser Variable innerhalb der Funktion macht, keinen Einfluss auf andere Variablen außerhalb der Funktion hat, auch wenn diese den gleichen Namen haben. Der Funktionsrumpf ist also der Gültigkeitsbereich einer solchen Variablen.
Um keine Missverständnisse aufkommen zu lassen: Variablen müssen nicht deklariert werden, wie dies in anderen Sprachen wie C und Java üblich ist. Variablen werden in Python implizit deklariert, wenn man sie definiert, d.h. ihnen einen Wert zuweist. Eine Variable erhält automatisch den richtigen Datentyp. Bei Problemen mit dieser Thematik empfehlen wir unser Kapitel über "Datentypen und Variablen", siehe Links auf der linken Seite.
Globale und lokale Variablen in Funktionen in Beispielen¶
Im folgenden Beispiel zeigen wir, wie globale Variablen innerhalb des Funktionsrumpfes benutzt werden können. Allerdings nur "lesend", also ohne den Wert zu ändern:
def f():
print(s)
s = "I love Paris in the summer!"
f()
Die Variable s wird definiert, in dem ihr die Zeichenkette "I love Paris in the summer!" zugeordnet wird. Diese Definition erfolgt vor dem Funktionsaufruf f(). Der Funktionsrumpf von f() besteht nur aus der "print(s)"-Anweisung. Weil es keine lokale Variable s gibt, d.h. keine Zuweisung an s innerhalb des Funktionsrumpfes von f, wird der Wert der globalen Variablen s benutzt. Dieser Wert kann natürlich nicht verändert werden, wie wir weiter unten in diesem Kapitel sehen werden. Es wird also der String "I love Paris in the summer!" ausgegeben.
Es stellt sich aber die Frage, was passiert, wenn wir den Wert von s innerhalb der Funktion von f() verändern. Wird dies eine Auswirkung auf die globale Variable s haben? Wir testen dies im folgenden kleinen Skript:
def f():
s = "I love London!"
print(s)
s = "I love Paris!"
f()
print(s)
Wie sieht es aber aus, wenn wir das erste Beispiel mit dem zweiten Beispiel kombinieren, d.h. wir also zuerst auf s mittels print zugreifen, in der Hoffnung den globalen Wert zu erhalten, und dann s einen neuen Wert zuweisen? Indem wir s einen Wert zuweisen können, machen wir s zu einer lokalen Variable. Dadurch gäbe es s innerhalb des Funktionsrumpfes sowohl als globale als auch als lokale Variable. Python lässt diese Mehrdeutigkeit nicht zu und es kommt zu einer Fehlermeldung, wie wir im folgenden Beispiel sehen können:
def f():
print(s)
s = "I love London!"
print(s)
s = "I love Paris!"
f()
Eine Variable kann nicht sowohl lokal als auch global innerhalb des gleichen Blocks, hier der Funktionsrumpf, sein. Deswegen betrachtete Python s als eine lokale Variable innerhalb des Rumpfes. Da nun auf diese lokale Variable zugegriffen wird, bevor sie definiert worden ist, sie also noch keinen Wert erhalten hat, erfolgt die Fehlermeldung.
Man kann jedoch auf globale Variablen "schreibend" innerhalb einer Funktion zugreifen. Dazu muss man sie jedoch explizit mittels des Schlüsselwortes "global" als global deklarieren. Wir können dies im folgenden Beispiel sehen:
def f():
global s
print(s)
s = "Zur Zeit nicht, aber Berlin ist auch toll!"
print(s)
s = "Gibt es einen Kurs in Paris?"
f()
print(s)
Damit haben wir die Mehrdeutigkeit beseitigt.
Auf lokale Variablen einer Funktion kann von außen nicht zugegriffen werden:
def f():
s = "I am globally not known"
print(s)
f()
print(s)
Das folgende Beispiel zeigt eine wilde Kombination von lokalen und globalen Variablen und Funktionsparametern, um die obigen Sachverhalte nochmals per Beispiel zu vertiefen:
def foo(x, y):
global a
a = 42
x,y = y,x
b = 33
b = 17
c = 100
print(a,b,x,y)
a,b,x,y = 1,15,3,4
foo(17,4)
print(a,b,x,y)
Globale Variablen in verschachtelten Funktionen¶
Wir werden jetzt untersuchen, was passieren wird, wenn wir das globale Schlüsselwort in verschachtelten Funktionen verwenden. Das folgende Beispiel zeigt eine Situation, in der eine Variable 'Stadt' in verschiedenen Bereichen verwendet wird:
def f ():
Stadt = "Hamburg"
def g ():
global Stadt
Stadt = "Genf"
print ("Vor dem Aufruf von g:" + Stadt)
print ("Jetzt anrufen g:")
g()
print ("Nach dem Aufruf von g:" + Stadt)
f ()
print ("Wert der Stadt in der Hauptsache:" + Stadt)
Wir können sehen, dass die globale Anweisung innerhalb der verschachtelten Funktion g die Variable 'Stadt' der Funktion f nicht beeinflusst, d. H. Ihren Wert 'Hamburg' behält. Aus diesem Beispiel können wir auch ableiten, dass nach dem Aufruf von f () eine Variable 'Stadt' im Modul-Namespace existiert und den Wert 'Geneva' hat. Dies bedeutet, dass das globale Schlüsselwort in verschachtelten Funktionen keinen Einfluss auf den Namespace des umschließenden Namespace hat! Dies steht im Einklang mit dem, was wir im vorherigen Unterkapitel herausgefunden haben: Eine innerhalb einer Funktion definierte Variable ist lokal, sofern sie nicht explizit als global markiert ist. Mit anderen Worten, wir können auf einen Variablennamen in einem beliebigen umschließenden Bereich verweisen, aber wir können Variablennamen nur im lokalen Bereich neu binden, indem wir ihm zuweisen, oder im modulglobalen Bereich, indem wir eine globale Deklaration verwenden. Wir brauchen eine Möglichkeit, auch auf Variablen anderer Bereiche zuzugreifen. Der Weg dazu sind nichtlokale Definitionen, die wir im nächsten Kapitel erläutern werden.
nichtlokale Variablen¶
Python3 führte nichtlokale Variablen als neue Art von Variablen ein. Nichtlokale Variablen haben viel mit globalen Variablen gemeinsam. Ein Unterschied zu globalen Variablen besteht in der Tatsache, dass es nicht möglich ist, Variablen aus dem Modulbereich, d. H. Variablen, die nicht innerhalb einer Funktion definiert sind, mithilfe der nichtlokalen Anweisung zu ändern. Wir zeigen dies in den beiden folgenden Beispielen:
def f():
global Stadt
print(Stadt)
Stadt = "Frankfurt"
f()
Dieses Programm ist korrekt und gibt 'Frankfurt' als Ausgabe zurück. Wir werden "global" in "nonlocal" im folgenden Programm ändern:
def f():
nonlocal Stadt
print(Stadt)
Stadt = "Frankfurt"
f()
Dies zeigt, dass nichtlokale Bindungen nur innerhalb verschachtelter Funktionen verwendet werden können. Eine nichtlokale Variable muss im umschließenden Funktionsumfang definiert werden. Wenn die Variable nicht im umschließenden Funktionsbereich definiert ist, kann die Variable nicht im verschachtelten Bereich definiert werden. Dies ist ein weiterer Unterschied zur "globalen" Semantik.
def f ():
Stadt = "München"
def g ():
nonlocal Stadt
Stadt = "Zürich"
print ("Vor dem Aufruf von g:" + Stadt)
print ("Jetzt anrufen g:")
g()
print ("Nach dem Aufruf von g:" + Stadt)
Stadt = "Stuttgart"
f ()
print ("'Stadt' in der Hauptsache:" + Stadt)
Im vorherigen Beispiel wurde die Variable 'Stadt' vor dem Aufruf von g definiert. Wir erhalten einen Fehler, wenn er nicht definiert ist:
def f ():
#Stadt = "München"
def g ():
nonlocal Stadt
Stadt = "Zürich"
print ("Vor dem Aufruf von g:" + Stadt)
print ("Jetzt anrufen g:")
g()
print ("Nach dem Aufruf von g:" + Stadt)
Stadt = "Stuttgart"
f ()
print ("'Stadt' in der Hauptsache:" + Stadt)
Das Programm funktioniert einwandfrei - mit oder ohne die Zeile 'Stadt = "Munich"' innerhalb von f -, wenn wir "nonlocal" in "global" ändern:
def f ():
#Stadt = "München"
def g ():
global Stadt
Stadt = "Zürich"
print ("Vor dem Aufruf von g:" + Stadt)
print ("Jetzt anrufen g:")
g()
print ("Nach dem Aufruf von g:" + Stadt)
Stadt = "Stuttgart"
f ()
print ("'Stadt' in der Hauptsache:" + Stadt)
Es gibt jedoch einen großen Unterschied: Der Wert des globalen x wird jetzt geändert!