Variablen und Funktionsdefinitionen in Python
Lokale Variablen
Eine Variable, die ein einer Funktionsdefinition angelegt wird, heißt auch lokale Variable.
Beim Aufruf einer Funktion wird speziell für diesen Aufruf eine Bindungstabelle angelegt. Die Bindungen der lokalen Variablen werden in dieser Bindungstabelle eingetragen. Wenn der Aufruf endet, dann wird auch diese Bindungstabelle wieder aufgelöst.
In dem folgenden Programm werden also zwei lokale Variablen »x« angelegt (eine pro Aufruf und Bindungstabelle).
- Wir bezeichnen eine Folge von Eingaben hier auch als ein „Programm“
main.py
def f():
x = 2
print( x )f()
f()
print( x )
- Protokoll (frei übersetzt und verkürzt)
2
2Namensfehler: Der Name 'x' wurde nicht definiert.
Man kann von außen (von außerhalb der Suite) nicht auf eine lokale Variable einer Funktion zugreifen. Genausowenig kann man von einer Funktion auf eine lokale Variable einer anderen Funktion zugreifen.
Wenn es schon vorher eine Variable mit dem gleichen Namen gab, wird die vorher existierende Variable nicht durch die Variable in der Funktionsdefinition berührt.
- main.py
x = 8
def f():
x = 2
print( x )f()
print( x )
- Protokoll
2
8
Die beiden Variablen in »f« und »g« sind zwei voneinander unabhängige Variablen, auch wenn sie „zufällig“ denselben Namen haben.
- Funktionsdefinitionen
def f():
x = 2
print( x )def g():
x = 3
print( x )
Lokalen Namen und »del«
Normalerweise ist es nicht nötig, einzelne Namen mit »del« von ihrem Objekt zu entbinden.
Im Falle eines lokalen Namens endet dessen Bindung nämlich bereits automatisch mit dem Ende der Ausführung seiner Funktion.
- Funktionsdefinition
def f():
x = 2
print( x )
del x # ueberfluessig!
Die Verwendung von Funktionen mit lokalen Namen hat also auch den Vorteil, daß diese automatisch entbunden werden, sobald sie nicht mehr benötigt werden, wodurch potentiell Speicherplatz gespart wird.
Lokalen Namen und ›dir‹
main.py
z = 4
def f():
y = None
x = 2
print( dir() )f()
print( dir() )- Protokoll (gekürzt)
['x', 'y']
['f', 'z']
Anwendung Ein- und Ausgabe
Das folgende Beispiel zeigt das Einlesen einer Zahl und die Ausgabe eines Rechenergebnisses.
Man beachte, wie der Datentyp zuerst mit »int« von »str« nach »int« und dann später wieder mit »str« von »int« nach »str« gewandelt werden muß.
main.py
def Quadrieren():
x = int( input( 'Zahl? ' ))
print( 'Quadrat = ' + str( x*x ))Quadrieren()
- Verwendung der Funktion (Beispiel)
Zahl? 3
Quadrat = 9
Modulvariablen
Eine Variable, die außerhalb einer Funktionsdefinition angelegt wird, ist eine Modulvariable (ein in der Bindungstabelle des Moduls der Bindungsanweisung eingetragener Name), wird aber auch oft „globale Variable“ genannt.
Modulvariablen können in Funktionsdefinitionen verwendet werden.
main.py
x = 2
def f():
print( x )f()
- Protokoll
2
Falls jedoch in einer Funktion ein lokaler Name mit der gleichen Schreibweise wie eine Modulvariable verwendet wird, so verdeckt er diesen, selbst wenn die erste Bindung an den Namen erst nach der ersten Verwendung erfolgt.
main.py
x = 2
def f():
print( x )
x = 3f()
- Protokoll
Fehler: Der lokale Name 'x' wurde vor einer Bindung an ihn verwendet.
Will man in einer Funktionsdefinition schreibend auf eine Modulvariable zugreifen, kann man sie in der Funktionsdefinition mit »global« „deklarieren“, indem man eine global-Anweisung verwendet.
main.py
x = 8
def f():
global x
x = 2
print( x )print( x )
f()
print( x )
- Protokoll
8
2
2
»global« erlaubt auch das Anlegen neuer globaler Variablen aus einer Funktion heraus.
main.py
def f():
global x
x = 2
global math
import math
global g
def g():
print( "g" )f()
print( x )
print( math.floor( 7.2 ))
g()
- Protokoll
2
7
g
Anwendungsbeispiel
Die Funktion »decrement_i« soll »i« dekrementieren, aber nur, falls «i» größer als «0» ist.
main.py
def print_i():
print( f"{i = }" )def decrement_i():
global i
i -= i > 0i = 3; print_i()
decrement_i(); print_i()
decrement_i(); print_i()
decrement_i(); print_i()
decrement_i(); print_i()
decrement_i(); print_i()- Protokoll
i = 3
i = 2
i = 1
i = 0
i = 0
i = 0
Stilregeln
Der Gültigkeitsbereich eines Namens sollte immer möglichst klein sein.
Der Gültigkeitsbereich eines lokalen Namens einer Funktionsdefinition ist normalerweise kleiner als der Gültigkeitsbereich einer Namens, der zu der ganzen Moduldefinition gehört, in der sich die Funktionsdefinition befindet.
Daher sollten lokale Namen bevorzugt verwendet werden.
Im folgenden Skript könnte »old = …« Informationen eines anderen Programmteils löschen, falls dieser auch eine Variable namens »old« verwendet.
- Skript
from sys import getrecursionlimit
from sys import setrecursionlimit
# ...
old = getrecursionlimit()
setrecursionlimit( 2000 )
# ...
setrecursionlimit( old )
Im folgenden Skript kann »old = …« keine Informationen eines anderen Programmteils löschen, falls dieser auch eine Variable namens »old« verwendet.
- Skript
from sys import getrecursionlimit
from sys import setrecursionlimit
# ...
def f():
old = getrecursionlimit()
setrecursionlimit( 2000 )
# ...
setrecursionlimit( old )
f()
Entbinden von Namen
Das folgende Beispiel zeigt, wie jemand einen Namen löscht, um zu verdeutlichen, daß dieser nun nicht mehr benötigt wird.
- Quelltext
...
filename = "example.txt"
file = open( filename )
del filename
...
Da es aber ohnehin besser ist, wenn Programme in einzelnen Funktionen zerlegt werden, ist die folgende, in etwa äquivalente Vorgehensweise vielleicht besserer Stil
- Quelltext
...
def open_example():
filename = "example.txt"
return open( filename )file = open_example()
...
Hier wird der lokale Name »filename« stillschweigend am Ende des Funktionsablaufs wieder entbunden.
Übungsfragen
? Zugriffe auf globale Name
Welche Ausgabe erzeugt das folgende Programm?
main.py
i = 0
def f():
global i
i += 1f(); f(); f()
print( i )
Übungsaufgaben _
Für alle Funktionsdefinitionen in diesem Kapitel soll »def« verwendet werden und nicht »= lambda«.
/ Bindung _
Schreiben Sie die def-Definition einer Funktion »reset_a«, welche den Wert »0« an die globale Variable »a« bindet.
main.py
reset_a(); print( a )
a = 5; print( a )
reset_a(); print( a )- Protokoll
0
5
0
/ Erhöhen _
Schreiben Sie die def-Definition einer Funktion »inc_a«, welche die globale Variable »a« um »1« erhöht (hierzu darf angenommen werden, daß die globale Variable »a« eine Zahl enthält, die nicht zu groß oder zu klein ist).
main.py
reset_a()
inc_a()
inc_a()
a- Protokoll
2
/ Vertauschen _
Schreiben Sie die def-Definition einer Funktion »swap_ab«, welche die Inhalte der beiden globalen Variablen »a« und »b« miteinander vertauscht.
Zweifaches Vertauschen soll also den ursprünglichen Zustand wieder herstellen
main.py
a = 2; b = -9; print( a, b )
swap_ab(); print( a, b )
swap_ab(); print( a, b )a = 12; b = 8; print( a, b )
swap_ab(); print( a, b )
swap_ab(); print( a, b )
swap_ab(); print( a, b )- Protokoll
2 -9
-9 2
2 -912 8
8 12
12 8
8 12- Aussprache
- swap swɑp
/ Zufallszahlen erzeugen
Schreiben Sie die def-Definition einer Funktion »r«, ohne Aufruf eine Funktion der Standardbibliothek eine Zufallszahl zwischen 0 und 9 ergibt.
Dazu soll auch noch eine Modulvariable angelegt werden, die zunächst eine beliebige Zahl enthält.
Die Funktion soll dann einen festen positiven ganzzahligen Wert zu dieser Variablen addieren, das Ergebnis mit einem festen positiven ganzzahligen Wert multiplizieren und dann auf eine beliebige Weise dafür sorgen, daß der Wert in der Variablen verkleinert wird, falls er größer als 434623618712 ist.
Anschließend soll die Funktion aus dieser Variablen einen Wert ermitteln, der immer zwischen 0 und 9 liegt und als (mehr oder weniger „zufälliges“) Ergebnis zurückgeben.
Falls die Ergebnisse nach mehreren Aufrufen noch nicht als zufällig genug erscheinen, kann die Funktion noch variiert werden, um die Ergebnisse „zufälliger“ zu machen.
Aufrufe ⃗
Man kann sich nicht ohne weiteres sicher sein, daß eine Funktion bei einem Aufruf wirklich das vom Autor der Funktion vielleicht Beabsichtigte tut.
main.py
def f():
print( 'exit()' )f()
print = eval
f()
- Protokoll
exit()
☈
Verwendung nicht angelegter lokaler Variablen ⃗
Will man eine lokale Variable innerhalb der Funktion verwenden, so geht dies erst nachdem man ihr einen Wert zugewiesen hat. (Selbst, wenn es eine gleichnamige globale Variable gibt.)
main.py
def f():
print( x )
x = 2f()
- Protokoll (frei übersetzt)
Fehler: Die lokale Variable 'x' wurde vor einer Bindung an sie verwendet.
Dieselbe Fehlermeldung erscheint auch, wenn eine lokale Variable zwar angelegt, aber danach wieder gelöscht wird.
main.py
def f():
x = 2
del x
print( x )f()
- Protokoll (frei übersetzt)
Fehler: Die lokale Variable 'x' wurde vor einer Bindung an sie verwendet.
Ein »del x« am Anfang einer Funktion bezieht sich ebenfalls auf eine lokale Variable »x«. Da es eine solche in dem folgenden Beispiel nicht gibt, erscheint eine Fehlermeldung.
main.py
x = 9
def f():
del xf()
- Protokoll (frei übersetzt)
Fehler: Die lokale Variable 'x' wurde vor einer Bindung an sie verwendet.
Verwendung von »exec« ⃗
»exec« ⃗
main.py
x = 2
( lambda: exec( "x=3; print( x )" ))()
print( x )
( lambda: exec( "global x; x=3; print( x )" ))()
print( x )
- Protokoll
3
2
3
3
lokale Variablen ⃗
Code in »exec« kann nicht ohne weiteres in lokale Variablen schreiben.
main.py
def f():
x = 1
exec( "x = 2" )
print( x )
f()- Protokoll
1
Wir werden erst später Mittel kennenlernen, die es erlauben, Veränderungen an Variablen, die durch »exec« stattfanden, in lokale Variablen zurückzuschreiben.