19 Funktionen 

Aus der Mathematik kennen Sie den Begriff der Funktion, mit dem eine Zuordnungsvorschrift bezeichnet wird. Die Funktion ƒ(x)=x2 ordnet beispielsweise dem Parameter x sein Quadriertes zu. Eine Funktion im mathematischen Sinne besteht aus einem Namen, einer Liste von Parametern und einer Berechnungsvorschrift für den Funktionswert.
In der Programmierung findet sich das mathematische Konzept der Funktion wieder. Wir haben beispielsweise bereits die eingebaute Funktion len besprochen, die die Länge eines iterierbaren Objekts berechnet. Dazu bekommt sie das entsprechende Objekt als Argument übergeben und gibt das Ergebnis in Form eines Rückgabewertes zurück.
>>> len("Dieser String ist ein Argument")
30
Offensichtlich besteht hier eine gewisse Analogie zum mathematischen Begriff der Funktion. Eine Funktion in der Programmierung besteht aus einem Funktionsnamen, einer Liste von Funktionsparametern und einem Code-Block, dem Funktionskörper. Bei einem Funktionsaufruf wird dann der Funktionskörper unter Berücksichtigung der übergebenen Argumente ausgeführt. Eine Funktion in Python kann, wie len, einen Rückgabewert haben oder nicht.[ 62 ](In Python wird – anders als beispielsweise in PASCAL – nicht zwischen den Begriffen Funktion und Prozedur unterschieden. Unter einer Prozedur versteht man eine Funktion, die keinen Rückgabewert hat. )
Funktionen werden in der Programmierung dazu eingesetzt, um Redundanzen im Quellcode zu vermeiden. Das bedeutet, dass Code-Stücke, die in der gleichen oder einer ähnlichen Form öfter im Programm benötigt werden, nicht jedes Mal neu geschrieben, sondern in einer Funktion gekapselt werden. Diese Funktion kann dann an den Stellen, an denen sie benötigt wird, aufgerufen werden. Darüber hinaus bilden Funktionen ein elegantes Hilfsmittel, um einen langen Quellcode sinnvoll in Unterprogramme aufzuteilen. Das erhöht die Les- und Wartbarkeit des Codes.
Im Folgenden erläutern wir die Handhabung einer bestehenden Funktion am Beispiel von range. Vieles des hier Gesagten kennen Sie bereits aus Kapitel 8, »Funktionen, Methoden und Attribute«; wir möchten es an dieser Stelle trotzdem noch einmal wiederholen.
Die eingebaute Funktion range wurde in Abschnitt 5.2.6, »Die for-Schleife als Zählschleife« eingeführt und erzeugt ein iterierbares Objekt über eine begrenzte Anzahl fortlaufender ganzer Zahlen:
ergebnis = range(0, 10, 2)
Im Beispiel oben wurde range aufgerufen; man nennt dies den Funktionsaufruf. Dazu wird hinter den Namen der Funktion ein (möglicherweise leeres) Klammernpaar geschrieben. Innerhalb dieser Klammern stehen die Parameter der Funktion, durch Kommata getrennt. Wie viele es sind und welche Art von Parametern eine Funktion erwartet, hängt von der Definition der Funktion ab und ist sehr unterschiedlich. In diesem Fall benötigt range drei Parameter, um ausreichend Informationen zu erlangen. Die Gesamtheit der Parameter wird Funktionsschnittstelle genannt. Konkrete, über eine Schnittstelle übergebene Instanzen heißen Argumente. Ein Parameter hingegen bezeichnet einen Platzhalter für Argumente.
Nachdem die Funktion abgearbeitet wurde, wird ihr Ergebnis zurückgegeben. Sie können sich bildlich vorstellen, dass der Funktionsaufruf, wie er im Quelltext steht, durch den Rückgabewert ersetzt wird. Im Beispiel oben haben wir dem Rückgabewert von range direkt einen Namen zugewiesen und können fortan über ergebnis auf ihn zugreifen. So können wir beispielsweise in einer for-Schleife über das Ergebnis des range-Aufrufs iterieren:
>>> ergebnis = range(0, 10, 2)
>>> for i in ergebnis:
... print(i)
...
0
2
4
6
8
Es ist auch möglich, das Ergebnis des range-Aufrufs mit list in eine Liste zu überführen:
>>> liste = list(ergebnis)
>>> liste
[0, 2, 4, 6, 8]
>>> liste[3]
6
So viel vorerst zur Verwendung vordefinierter Funktionen. Python erlaubt es Ihnen, eigene Funktionen zu schreiben, die Sie nach demselben Schema verwenden können, wie es hier beschrieben wurde. Im nächsten Abschnitt werden wir uns damit befassen, wie Sie eine eigene Funktion erstellen.
19.1 Schreiben einer Funktion 

Bevor wir uns an konkreten Quelltext wagen, möchten wir rekapitulieren, was eine Funktion ausmacht, was also bei der Definition einer Funktion anzugeben ist:
- Eine Funktion muss einen Namen haben, über den sie in anderen Teilen des Programms aufgerufen werden kann. Die Zusammensetzung des Funktionsnamens erfolgt nach denselben Regeln wie die Namensgebung einer Referenz.[ 63 ](Das bedeutet, dass sich der Funktionsname aus großen und kleinen Buchstaben, Zahlen sowie dem Unterstrich (»_«) zusammensetzen, allerdings nicht mit einer Zahl beginnen darf. Seit Python 3.0 dürfen auch Buchstaben verwendet werden, die nicht im englischen Alphabet enthalten sind. )
- Eine Funktion muss eine Schnittstelle haben, über die Informationen vom aufrufenden Programmteil in den Kontext der Funktion übertragen werden. Eine Schnittstelle kann aus beliebig vielen (unter Umständen auch keinen) Parametern bestehen. Funktionsintern wird jedem dieser Parameter ein Name gegeben. Sie lassen sich dann wie Referenzen im Funktionskörper verwenden.
- Eine Funktion muss einen Wert zurückgeben. Jede Funktion gibt automatisch None zurück, wenn der Rückgabewert nicht ausdrücklich angegeben wurde.
Zur Definition einer Funktion wird in Python das Schlüsselwort def verwendet. Syntaktisch sieht die Definition folgendermaßen aus:
Abbildung 19.1 Definition einer Funktion
Nach dem Schlüsselwort def steht der gewählte Funktionsname. Dahinter werden in einem Klammernpaar die Namen aller Parameter aufgelistet. Nach der Definition der Schnittstelle folgen ein Doppelpunkt und, eine Stufe weiter eingerückt, der Funktionskörper. Bei dem Funktionskörper handelt es sich um einen beliebigen Code-Block, in dem die Parameternamen als Referenzen verwendet werden dürfen. Im Funktionskörper dürfen auch wieder Funktionen aufgerufen werden.
Betrachten wir einmal die konkrete Implementierung einer Funktion, die die Fakultät einer ganzen Zahl berechnet und das Ergebnis auf dem Bildschirm ausgibt:
def fak(zahl):
ergebnis = 1
for i in range(2, zahl+1):
ergebnis *= i
print(ergebnis)
Anhand dieses Beispiels können Sie gut nachvollziehen, wie der Parameter zahl im Funktionskörper verarbeitet wird. Nachdem die Berechnung erfolgt ist, wird ergebnis mittels print ausgegeben. Die Referenz zahl ist nur innerhalb des Funktionskörpers definiert und hat nichts mit anderen Referenzen außerhalb der Funktion zu tun.
Wenn Sie das obige Beispiel jetzt speichern und ausführen, werden Sie feststellen, dass zwar keine Fehlermeldung angezeigt wird, aber auch sonst nichts passiert. Nun, das liegt daran, dass wir bisher nur eine Funktion definiert haben. Um sie konkret im Einsatz zu sehen, müssen wir sie mindestens einmal aufrufen. Folgendes Programm liest in einer Schleife Zahlen vom Benutzer ein und berechnet deren Fakultät mithilfe der soeben definierten Funktion:
def fak(zahl):
ergebnis = 1
for i in range(2, zahl+1):
ergebnis *= i
print(ergebnis)
while True:
eingabe = int(input("Geben Sie eine Zahl ein: "))
fak(eingabe)
Sie sehen, dass der Quellcode in zwei Komponenten aufgeteilt wurde: zum einen in die Funktionsdefinition oben und zum anderen in das auszuführende Hauptprogramm unten. Das Hauptprogramm besteht aus einer Endlosschleife, in der die Funktion fak mit der eingegebenen Zahl als Parameter aufgerufen wird.
Betrachten Sie noch einmal die beiden Komponenten des Programms. Es wäre im Sinne der Kapselung der Funktionalität erstrebenswert, das Programm so zu ändern, dass sich das Hauptprogramm allein um die Interaktion mit dem Benutzer und das Anstoßen der Berechnung kümmert, während das Unterprogramm fak die Berechnung tatsächlich durchführt. Das Ziel dieses Ansatzes ist es vor allem, dass die Funktion fak auch in anderen Programmteilen zur Berechnung einer weiteren Fakultät aufgerufen werden kann. Dazu ist es unerlässlich, dass fak sich ausschließlich um die Berechnung kümmert. Es passt nicht in dieses Konzept, dass fak das Ergebnis der Berechnung selbst ausgibt.
Idealerweise sollte unsere Funktion fak die Berechnung abschließen und das Ergebnis an das Hauptprogramm zurückgeben, sodass die Ausgabe dort erfolgen kann. Dies erreichen Sie durch das Schlüsselwort return, das die Ausführung der Funktion sofort beendet und einen eventuell angegebenen Rückgabewert zurückgibt.
def fak(zahl):
ergebnis = 1
for i in range(2, zahl+1):
ergebnis *= i
return ergebnis
while True:
eingabe = int(input("Geben Sie eine Zahl ein: "))
print(fak(eingabe))
Eine Funktion kann zu jeder Zeit im Funktionsablauf mit return beendet werden. Die folgende Version der Funktion prüft vor der Berechnung, ob es sich bei dem übergebenen Parameter um eine negative Zahl handelt. Ist das der Fall, wird die Abhandlung der Funktion abgebrochen:
def fak(zahl):
if zahl < 0:
return None
ergebnis = 1
for i in range(2, zahl+1):
ergebnis *= i
return ergebnis
while True:
eingabe = int(input("Geben Sie eine Zahl ein: "))
ergebnis = fak(eingabe)
if ergebnis is None:
print("Fehler bei der Berechnung")
else:
print(ergebnis)
In der zweiten Zeile des Funktionskörpers wurde mit return None explizit der Wert None zurückgegeben, was nicht unbedingt nötig ist. Der folgende Code ist äquivalent:
if zahl < 0:
return
Vom Programmablauf her ist es egal, ob Sie None explizit oder implizit zurückgeben. Aus Gründen der Lesbarkeit ist return None in diesem Fall trotzdem sinnvoll, denn es handelt sich um einen ausdrücklich gewünschten Rückgabewert. Er ist Teil der Funktionslogik und nicht bloß ein Nebenprodukt des Funktionsabbruchs.
Die Funktion fak, wie sie in diesem Beispiel zu sehen ist, kann zu jeder Zeit zur Berechnung einer Fakultät aufgerufen werden, unabhängig davon, in welchem Kontext diese Fakultät benötigt wird.
Selbstverständlich können Sie in Ihrem Quelltext mehrere eigene Funktionen definieren und aufrufen. Das folgende Beispiel soll bei Eingabe einer negativen Zahl keine Fehlermeldung, sondern die Fakultät des Betrags dieser Zahl ausgeben:
def betrag(zahl):
if zahl < 0:
return -zahl
else:
return zahl
def fak(zahl):
ergebnis = 1
for i in range(2, zahl+1):
ergebnis *= i
return ergebnis
while True:
eingabe = int(input("Geben Sie eine Zahl ein: "))
print(fak(betrag(eingabe)))
Für die Berechnung des Betrags einer Zahl gibt es in Python auch die Built-in Function abs. Diese werden Sie noch in diesem Kapitel kennenlernen.