Abschnitt 8 · Lektion 5
Gültigkeitsbereich
Jede Funktion in diesem Abschnitt hat eigene Variablen, text in euro, preis in kaffee,
rein und raus in bilanz. Außerhalb ihrer Funktion hat keine davon je eine Rolle gespielt.
Dahinter steckt eine Regel, der Gültigkeitsbereich (scope) einer Variablen. Das ist der Bereich
im Code, in dem es sie gibt.
Was in der Funktion bleibt
def brutto(netto):
ergebnis = round(netto * 1.19, 2)
return ergebnis
print(brutto(100))
print(ergebnis) ergebnis bekommt in der Funktion seinen Wert, und return gibt diesen Wert nach draußen. Den
Namen aber nicht. Die letzte Zeile endet mit NameError: name 'ergebnis' is not defined, als hätte
es ergebnis nie gegeben. Und draußen hat es das auch nie.
Eine Variable, die in einer Funktion einen Wert bekommt, ist lokal (local). Es gibt sie nur in
dieser Funktion, und nur, solange die Funktion läuft. Wenn sie fertig ist, ist der Name weg, und
beim nächsten Aufruf fängt er von vorn an. Parameter sind auch lokal, netto gibt es draußen
genauso wenig.
Was eine Funktion nach draußen geben will, gibt sie mit return zurück. Wo sie aufgerufen wird,
bekommt der Wert dann einen eigenen Namen.
Das schützt die Funktion. Sie darf ergebnis, summe oder text nennen, was sie will, ohne
nachzusehen, ob es draußen schon etwas mit diesem Namen gibt. Die Funktion bilanz nennt ihre
Summen rein und raus, und ein rein draußen wäre ihr egal.
Lesen von draußen
MWST = 19
def brutto(netto):
return round(netto * (1 + MWST / 100), 2)
print(brutto(100))
print(brutto(4.20)) Umgekehrt geht etwas. MWST steht draußen, ganz oben in der Datei, und die Funktion liest es
trotzdem. Wenn Python einen Namen in der Funktion nicht findet, sieht es draußen in der Datei nach.
Namen, die dort stehen, heißen global (global), weil es sie in der ganzen Datei gibt.
Der Name in Großbuchstaben ist eine Abmachung unter Python-Leuten. So schreibt man Werte, die sich
während des ganzen Programms nicht ändern, eine Konstante (constant). Python selbst ist das
egal, du könntest MWST ändern. Aber jeder, der den Code liest, weiß, dass sich der Wert nicht
ändern soll. Für eine Konstante ist Lesen von draußen genau richtig.
Ändern von draußen
kontostand = 100
def zuruecksetzen():
kontostand = 0
print("In der Funktion:", kontostand)
zuruecksetzen()
print("Draußen:", kontostand) Beim Ändern ist es anders. Die Funktion setzt kontostand auf 0, und in der Funktion steht auch 0.
Draußen stehen danach aber immer noch 100 Euro. Mit der Zuweisung in der Funktion wurde nicht der
Kontostand draußen geändert. Es wurde eine neue, lokale Variable angelegt, die zufällig genauso
heißt. Zwei Variablen, ein Name, und welche gemeint ist, hängt am Ort.
Im Reiter Debug kannst du das nachsehen. Wenn du das Beispiel aufzeichnest, steht draußen am
Rand kontostand mit 100, sobald die erste Zeile gelaufen ist. Im ersten Schritt in der Funktion
steht dort gar nichts, weil die Funktion noch keine eigenen Namen hat. Erst vor dem print taucht
kontostand mit 0 auf. Die 100 von draußen siehst du in der Funktion nicht, dort stehen nur ihre
eigenen Namen. Im letzten Schritt, wieder draußen, steht dann wieder die 100.
kontostand = 100
def einzahlen(betrag):
kontostand = kontostand + betrag
einzahlen(50)
print(kontostand) Und hier wird es seltsam. Diese Funktion will den Kontostand von draußen lesen und gleich ändern.
Das Programm endet mit
UnboundLocalError: cannot access local variable 'kontostand' where it is not associated with a value.
Auf Deutsch heißt das etwa, dass auf die lokale Variable kontostand nicht zugegriffen werden kann,
weil sie noch keinen Wert hat.
Dabei steht draußen doch einer. Python entscheidet aber für die ganze Funktion auf einmal, ob ein
Name lokal ist, und zwar bevor sie läuft. Steht irgendwo in der Funktion kontostand = …, ist
kontostand dort überall lokal, auch rechts vom Gleichheitszeichen in derselben Zeile. Und diese
lokale Variable soll gelesen werden, bevor sie ihren ersten Wert hat.
Die Meldung gehört zu den verwirrendsten, die Python hat. Fast immer heißt sie, dass eine Funktion versucht, eine Variable von draußen zu ändern.
Der Weg über global
kontostand = 100
def einzahlen(betrag):
global kontostand
kontostand = kontostand + betrag
einzahlen(50)
print(kontostand) Es gibt einen Weg, das trotzdem zu tun. Mit global kontostand in der ersten Zeile der Funktion
sagst du Python, dass hier der kontostand von draußen gemeint ist, auch zum Ändern. Danach steht
draußen 150.
In diesem Kurs kommt global nicht vor, und dafür gibt es einen praktischen Grund. Eine Funktion
mit global hängt an einem Wert, der irgendwo anders steht und den jede andere Funktion genauso
ändern darf. Wenn du wissen willst, warum der Kontostand am Ende falsch ist, musst du jede Funktion
lesen, die ihn anfasst, und zwar in der Reihenfolge, in der sie aufgerufen wurden. Einzeln
ausprobieren kannst du so eine Funktion auch nicht, denn jeder Aufruf ändert das echte Konto.
Hinein über Parameter, hinaus über return
def einzahlen(stand, betrag):
return stand + betrag
kontostand = 100
kontostand = einzahlen(kontostand, 50)
print(kontostand)
print(einzahlen(0, 20))
print(kontostand) Der andere Weg ist der aus den Lektionen davor. Die Funktion bekommt den Stand als Parameter,
rechnet und gibt den neuen Stand zurück. Draußen entscheidet eine einzige Zeile, ob sich der
Kontostand ändert, nämlich kontostand = einzahlen(kontostand, 50). Wer den Code liest, sieht genau
an dieser Zeile, dass er es tut.
Außerdem lässt sich die Funktion jetzt mit beliebigen Zahlen ausprobieren, ohne dass das echte Konto
davon etwas merkt. einzahlen(0, 20) gibt 20 zurück, und kontostand steht danach immer noch bei
150 Euro. Eine Funktion, die nur über Parameter und return mit dem Rest des Programms zu tun hat,
kannst du so für sich allein prüfen. Auch pruefen.py macht es seit Lektion 8.2 so und ruft deine
Funktionen mit eigenen Werten auf, um nachzusehen, was zurückkommt.
Was die Aufgabe will
Ein kleines Programm führt ein Konto mit global und rechnet falsch. Die Funktion, die nur
nachsehen soll, ob das Geld reicht, hebt dabei nämlich gleich ab. Die drei Funktionen sollen so
umgebaut werden, dass sie den Stand bekommen und zurückgeben, und dann stimmt auch die Rechnung.
Zum Mitnehmen
Ein Name, der in einer Funktion entsteht, ist draußen unbekannt und mit dem Ende der Funktion weg. Namen von außerhalb kann sie ohne Weiteres lesen. Soll sich draußen etwas ändern, bekommt sie den Stand als Parameter und gibt den neuen mit return zurück.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.
Was in dieser Lektion steckt
-
Artikel mit 6 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe, dein Code läuft auf einem Server
Öffnet sich mit dem Basis Konto.