Python Tutorial, Teil 5 Rückgabe von Werten und Objekten durch Funktionen
In diesem Teil unseres Python-Tutorials machen wir uns mit globalen und lokalen Variablen vertraut. Dementsprechend stehen auch die Rückgabewerte von Funktionen und Methoden im Fokus, den Umgang mit Aufruf-Argumenten haben wir ja bereits eingehend betrachtet.

Funktionen gibt es in allen Programmiersprachen. Wir haben diese Konstrukte in Teil 3 unseres Python-Workshops zunächst grob als Äquivalent zu Prozeduren, Unterprogrammen, Methoden oder Routinen bezeichnet. Bei genauerem Hinsehen besteht aber durchaus ein Unterschied zwischen Funktionen, Methoden und Prozeduren, da nämlich Funktionen im Gegensatz zu letzteren immer einen Wert zurückliefern.
Streng genommen wäre unsere Fibonacci-Funktion aus Teil 3 also gar keine Funktion, da ihr ja die obligatorische return-Anweisung fehlt. Allerdings gilt in Python, dass auch Funktionen ohne explizite return-Anweisung einen Wert zurückgeben, nämlich „none“, jedoch unterdrückt der Python-Interpreter die Ausgabe von „none“, wenn es sich um den einzigen Ausgabewert handelt. Wer das nicht glaubt, kann die Ausgabe mit einer print()-Anweisung (Funktion) erzwingen.
Globale und lokale Variablen
Funktionen in Python bilden bei ihrem Aufruf einen eigenen lokalen Namensraum, der sämtliche Bezeichner im Funktionskörper entweder in Form einer Zuweisung oder als Elemente einer Parameterliste neu definiert. Konkret bedeutet das: Python legt diese Bezeichner gemeinsam mit den ihnen zugeordneten Objekten in einer lokalen Symbol-Tabelle ab.
Im Funktionsrumpf verwendete Variablennamen sind demnach verschieden von etwaigen außerhalb der Funktion verwendeten gleichlautenden Variablen oder anders ausgedrückt: Python unterscheidet wie die meisten anderen Programmiersprachen auch zwischen lokalen und globalen Variablen.
Findet der Python-Interpreter im Funktionsrumpf nämlich einen Bezeichner, sucht er dessen Namen immer zuerst in der lokalen Symbol-Tabelle. Wird er dort nicht fündig, fahndet er in der lokalen Symbol-Tabelle der „umgebenden“ Funktion, dann in globalen Symbol-Tabelle und zuletzt in der Symbol-Tabelle für die fest eingebauten Namen.
Dies ist der Grund dafür, dass man einer globalen Variablen innerhalb des lokalen Namensraums einer Funktion keinen neuen Wert zuweisen kann. Wir hatten ja schon gesehen, dass die Typ-Deklaration bei Python durch den Prozess der Zuweisung geschieht. Somit kann man einer Variablen, die den gleichen Namen hat wie eine „außerhalb“ der Funktion, innerhalb derselben durchaus einen neuen Wert zuweisen. Allerdings entsteht dadurch eine neue lokalen Variable mit gleichem Namen.
Da diese lokale Variable dann aber die namensgleiche globale Variable überlagert, verhindert sie einen lesenden Zugriff auf diese globale Variable. Allgemein ist ein lesender Zugriff auf globale Variablen nämlich immer möglich, während ein schreibender Zugriff stets den dazu vorgesehenen global-Befehl benötigt.
Rückgabewerte von Funktionen
Was man im Zusammenhang mit der Definition von Funktionen ebenfalls berücksichtigen muss, ist die Art und Weise der Verarbeitung übergebener Argumente. So werden nämlich die beim Funktionsaufruf übergebenen Argumente immer den formalen Parametern der Parameterliste zugeordnet und somit auch der lokalen Symboltabelle der Funktion zugefügt. Argumente werden also bei Python „call by value“ übergeben, allerdings ist der Wert selbst immer eine Referenz auf ein Objekt und keinesfalls das Objekt selbst.
Ruft eine Funktion eine andere Funktion auf, wird für diesen Aufruf eine neue lokale Symbol-Tabelle generiert. Außerdem wird beim Definieren einer Funktion der Funktionsnamen in die lokale Symbol-Tabelle eingetragen. Der „Wert“ des Funktionsnamens besitzt einen Typ, den der Python-Interpreter als benutzerdefinierte Funktion identifiziert. Allerdings kann man diesen Wert einem anderen Namen zuweisen, der dann genau wie der ursprüngliche als Funktion verwendbar ist, quasi eine Art Umbenennung.
Derzeit hört unsere Fibonacci-Funktion aus Teil 3 noch auf den Namen „fibo“, wie man durch Eingabe des Funktionsnamens auch ohne Argumente leicht verifizieren kann. Eine Umbenennung kann dann durch Eingeben von
fib = fibo
erfolgen.
Rückgabe von Objekten
Werfen wir unter Berücksichtigung dieser Erkenntnisse noch einmal einen Blick auf unsere Fibonacci-Funktion aus dem letzten Teil.
def fibo(n): # Gibt Fibonacci-Reihe bis n aus.
x, y = 0, 1
while y < n:
print (y, end=" ")
x, y = y, x+y
# Rufe die Fibo-Funktion für n=100 auf:
fibo(100)
Hinsichtlich der möglichen Rückgabewerte (d.h. der geschilderten Eigenschaften von Rückgabewerten) könnten wie diese Funktion nun umschreiben bzw. erweitern, wobei die neu hinzugekommenen Zeile fett hervorgehoben sind. Statt nämlich wie vorher in der while-Schleife in jedem Durchlauf den jeweiligen Funktionswert direkt mit einer print-Anweisung auszugeben, definieren wir hier zuerst ein Listen-Objekt, wobei sich die Liste im Verlauf jedes Schleifendurchlaufs mit dem jeweiligen Ergebniswert (Funktionswert) des Fibonacci-Algorithmus füllt.
Am Ende der Funktion steht dann die Rückgabe des Funktionswertes, in diesem Fall des Listen-Objektes, mit den betreffenden Elementen. Diese Schreibweise macht den Funktions-Charakter unserer Fibonacci-Funktion deutlicher, da wir explizit die return-Anweisung verwenden, um den Funktionswert zurückzugeben, der eben auch ein (Listen-) Objekt sein kann.
def fibo(n): # Gibt Fibonacci-Reihe bis n aus.
ergebnis = list()
x, y = 0, 1
while y < n:
ergebnis = ergebnis + [x]
x, y = y, x+y
return ergebnis
# Rufe die Fibo-Funktion für n=100 auf:
fibo(100)
Was sind Methoden?
Wir wissen nun etwas genauer, was man unter Python unter einer Funktion versteht. Was aber versteht man unter einer Methode? Dies erschließt sich am besten, wenn wie die Fibonacci-Funktion noch ein weiteres Mal etwas umschreiben:
def fibo(n): # Gibt Fibonacci-Reihe bis n aus.
ergebnis = list()
x, y = 0, 1
while y < n:
ergebnis.append(x)
x, y = y, x+y
return ergebnis
# Rufe die Fibo-Funktion für n=100 auf:
fibo(100)
In diesem Beispiel ruft nämlich die Anweisung „ergebnis.append(x)“ die Methode „append“ auf, welche eine fest eingebaute Methode eines „Liste“-Objektes ist, das hier „ergebnis“ heißt. Unter einer Methode versteht man in Python immer einer Funktion, die fest zu einen Objekt gehört, was durch die Punkt-Schreibweise (objekt.methodenname) kenntlich gemacht wird, wobei „objekt“ auf der linken Seite auch ein „Ausdruck“ sein könnte.
Der rechte Teil „methodenname“ ist dann der Name der hier definierten Methode, die von Typ des jeweiligen Objektes definiert wird. Da also unterschiedliche Typen auch unterschiedliche Methoden definieren, können die Methoden unterschiedlicher Typen den gleichen Namen haben. Darüber hinaus kann man in Python unter Verwendung von Klassen auch eigene Objekttypen definieren.
Die hier verwendete Methode „append“ ist allerdings eine, die fest für ein Listen-Objekt vordefiniert ist. So kennt der Datentyp list neben der Methode „append“ durchaus noch weitere Methoden, wie z. B. extend, insert, remove, pop, index, count, sort und reverse.
Während z. B.
<Name des Listen-Objektes>.append (x)
ein neues Element am Ende der Liste anhängt, was ohne Verwendung dieser Methode mittels
a[len(a):] = [x]
erfolgen müsste, erweitert
<Name des Listen-Objektes>.extend (Y)
die Liste, indem sämtliche Elemente der gegebenen Liste (Y) an die bestehende Liste (z. b. „ergebnis“) angehängt werden, was dem Ausdruck
a[len(a):] = Y
entspräche, wobei Y ebenfalls eine Liste ist.
(ID:45192109)