11B: Geltungsbereich von Variablen

Lektion 11 hat drei Teile A, B, C, die in beliebiger Reihenfolge ausgeführt werden können.

In dieser Lektion erklären wir ein Konzept, das wir variable scope (etwa: Geltungsbereich von Variablen) nennen. Die wichtigste Idee ist, dass es möglich ist, zwei unterschiedliche Variablen mit dem selben Namen zu haben, wann immer sie einen unterschiedlichen „scope“ haben. Das macht es viel einfacher, Programme zu schreiben oder zu bearbeiten, besonders große.

Ein Beispiel für „variable scopes“

Für dieses Beispiel wird ein Teil unseres Programms die folgende Funktion sein:

def square(x):
   value = x * x
   return value
Dies ist eine Funktion, die das Quadrat der Zahl x berechnet; zum Beispiel gibt square(5) den Wert 25 zurück. Aber nehmen wir jetzt einmal an, wir riefen square von einem anderen Teil des Programms auf, der außerdem auch eine value Variable für einen anderen Zweck verwendet:

# Hier beginnt das Hauptprogramm
value = 17
fivesquared = square(5)
print(fivesquared, value)
Die Frage ist, was wird in diesem Szenario ausgegeben? Es gibt zwei Möglichkeiten, wenn wir nicht wissen, wie Python funktioniert:

  1. Eine Möglichkeit ist, dass Python erkennt, dass die zwei value Variablen irgendwie „auseinandergehalten“ werden. Der Aufruf von square wird 25 liefern, aber der Wert von value im Hauptprogramm wird bei 17 bleiben, und wir sehen den Output 25 17.
  2. Die andere Möglichkeit ist, dass, wenn square ausgeführt wird, es den Wert von value mit 25 überschreibt, und wir sehen den Output 25 25.

Lass uns sehen, was tatsächlich passiert!

Wir sehen, dass Pythons Verhalten konsistent ist mit Möglichkeit #1. Tatsächlich ist es so, dass, wann immer du eine Funktion aufrufst, du keine Variablen beeinflussen kannst, die außerhalb der Funktion definiert sind. Statt dessen ist es so, dass jedes Statement, das Variablen Werte zuweist, nur eine „lokale“ (d.h. örtliche) Variable beeinflusst, die sich „im“ Funktionsaufruf befindet. Der Grund dafür, dass Python und die meisten anderen Sprachen so funktionieren: So ist es viel einfacher, lange Programme mit einer Vielzahl an Funktionen zu schreiben. Wenn wir eine neue Funktion definieren, können wir in der Funktion beliebige Variablennamen verwenden (inklusive von häufigen Namen wie result,temp und i), selbst wenn sie anderswo aus anderen Gründen benutzt werden.

Um dies im Detail zu sehen, siehe dir "Schritt 6 von 8" im Visualisierer an. Beachte, dass es dort zwei verschiedene value Variablen gibt: eine in der square Funktion und eine außerhalb (im "globalen" Bereich).

Multiple-Choice-Übung: Inner and Outer
Was ist die Ausgabe des folgenden Programms?

x = "outer"
def xReplace(value):
   x = value
xReplace("inner")
print(x)
Korrekt! Das Statement x = value betrifft nur die örtliche Version der Variable x innerhalb der Funktion. Die globale Version von x verändert sich nicht. (also ist die Funktion xReplace nutzlos und hat niemals einen Effekt.)

Ein ähnliches Konzept wie scope ist namespace. Ein Namespace ist sowas wie ein Bereich für ein Modul. Also auch wenn du ein ganzes Modul importierst (wie z.B. math), das den Variablennamen x irgendwo verwendet, überschneidet es sich nicht mit der Variable x, die von deinem Programm benutzt wird, da sie in unterschiedlichen Namespaces liegen.

Scoping Regeln: Hinausblicken

Es gibt Situationen, bei denen wir Variablen von lokalen und globalen Bereichen vermischen möchten. Ein übliches Beispiel ist, dass wir eine gemeinsame Variable am Anfang des Programms initialisiert haben und außerdem möchten, dass Funktionen in der Lage sind, die Variable zu lesen.

Beispiel
Eine globale Variable von innerhalb einer Funktion auslesen

Hier beinhaltet der lokale Bereich keine Variable, die favouriteTopping genannt ist, aber dies hatte keinen Fehler zur Folge. Pythons Regel für die Auswertung von Variablen ist: Wird eine Variable ausgewertet, die nicht im lokalen Bereich existiert, dann sucht Python sie im globalen Bereich. In unserem Fall wurde favouriteTopping tatsächlich im globalen Bereich gefunden. (In einem allgemeineren Fall mit dem Körper einer Funktion, der eine andere Funktion aufruft, würdest du drei Bereiche haben; Python sucht eine Variable zuerst im „lokalsten“ Bereich und arbeitet sich dann Schritt für Schritt zum globalen Bereich vor, bis die Variable gefunden wird.)

Zwei der Beispiele oben, mit orderPizzas und xReplace, sind syntaktisch fast identisch. Warum erzeugt Python eine neue lokale Variable x in xReplace, aber keine neue favouriteTopping in orderPizzas? Pythons Regel ist die folgende: wenn man die Variable nur ausliest, dann wird keine neue lokale Variable erzeugt; aber sobald man der Variable einen neuen Wert gibt, dann wird sie im gesamten Funktionskörper als lokale Variable behandelt. (Das ist der üblichste Grund für UnboundLocalError: lies dazu diese zwei Fragen [1, 2] in der offiziellen Python-Dokumentation.)

Funktionsargumente werden immer als neue lokale Variablen behandelt, wie es das folgende nicht funktionierte Codefragment illustriert (es versucht die Variable g auf 0 zu setzen, aber es versagt).

Globale Änderungen

Wie viele andere Dinge, funktioniert der normale Ablauf wie oben beschrieben für 99% aller Situationen. Aber in den übrigen 1% willst du vielleicht wirklich innerhalb einer Funktion eine globale Variable ändern. Das geht mit Python, indem du das global Statement verwendest.

Hier ist eine Modifikation des früheren xReplace Beispiels; indem die Variable in einer Funktion als global deklariert wird, kannst du die globale Variable innerhalb der Funktion ändern.

Wie wir früher erwähnten, braucht man nicht die global Angabe um eine globale Variable zu lesen, nur um zu ändern. Du hast nun diese Lektion beendet und kannst zur nächsten gehen.