Eine Funktion besteht aus einem Funktionsnamen, einer Liste von Funktionsparametern und einem
Code-Block, dem Funktionskörper. Eine Funktion in Python kann einen Rückgabewert haben oder nicht.
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.
Zur Definition einer Funktion wird in Python das Schlüsselwort def verwendet.
def Funktionsname(parameter_1, ..., parameter_n):
Anweisung
...
Anweisung
Eine Funktion kann über ihren Namen nicht nur aufgerufen, sondern auch wie eine Instanz behandelt werden.
So ist es beispielsweise möglich, den Typ einer Funkton abzufragen.
def fak():
Anweisung
type(fak) => <class 'function'>
p = fak
p(5)
Funktionen sind in Python genauso Instanzen wie beispielsweise Zahlen oder String.
Ein optionaler Parameter muss funktionsintern mit einem Wert vorbelegt sein, üblicherweise einem
Standardwert, der in einem Großteil der Funktonsaufrufe ausreichend ist. Ein optionaler Parameter kann
beim Funktionsaufruf weggelassen werden.
def summe(a, b, c = 0, d = 0):
return a + b + c + d
Ein optionaler Parameter darf nur am Ende einer Funktionsschnittstelle stehen.
Neben den bislang verwendeten sogenannten Positional Argumets (Positionsparameter) gibt es in Python
eine weitere Möglichkeit, Parameter zu übergeben. Solche Parameter werden Keyword Arguments
(Schlüsselwortparameter) genannt. An der Funktionsdefinition ändert sich nichts.
Beispiel Aufruf: summe(d = 1, b = 3, c = 2, a = 1)
Schlüsselwortparameter können in beliebiger Reihenfolge angegeben werden.
Es ist möglich, beide Formen der Parameterübergabe zu kombinieren. Dabei ist zu beachten, dass keine
Positional Arguments auf Keyword Arguments folgen dürfen.
Für beide Formen der Parameterübergabe (Positional und Keyword) gibt es eine Notation, die es einer
Funktion ermöglicht, beliebig viele Parameter entgegenzunehmen.
Für Parameter beliebiger Anzahl ist dem Parameter ein Stern (*) voranzuschreiben:
def funktion(a, b, *weitere):
Der Parameter beliebiger Anzahl referenziert fortan ein Tupel.
Diese Art, einer Funktion das Entgegennehmen beliebig vieler Parameter zu ermöglichen, funktioniert ebenso
für Keyword Arguments. Der Parameter, der alle weiteren Instanzen enthalten soll, muss in der
Funktionsdefinition mit zwei Sternen (**) geschrieben werden:
def funktion(a, b, **weitere):
Der Parameter beliebiger Anzahl referenziert fortan ein Dictionary.
Reine Schlüsselwortparameter (engl. keyword-only parameters) werden bei der Funktionsdefinition
nach dem Parameter geschrieben, der beliebig viele Positionsargumente aufnimmt:
def funktion(a, b, *c, d, e):
d und e sind reine Schlüsselwortparameter.
Wenn zusätzlich die Übergabe beliebig vieler Schlüsselwortparameter ermöglicht werden soll, folgt
die dazu notwendige **-Notation nach den reinen Schlüsselwortparametern am Ende der Funktionsdefinition.
def funktion(a, b, *args, d, e, **kwargs):
Es ist auch möglic, reine Schlüsselwortparameter zu definieren, ohne gleichzeitig beliebig viele
Positionsparameter zuzulassen. Dazu werden die reinen Schlüsselwortparameter in der Funktionsschnittstelle
durch einen * von den Positionsparametern getrennt:
def funktion(a, b, *, c, d):
Der Vorgang, eine in einem iterierbaren Objekt gespeicherte Liste von Argumenten direkt einer Funktion
übergeben zu können, wird Entpacken genannt. Das Entpacken eines iterierbaren Objekts geschieht
dadurch, dass der Funktion das Objekt mit einem vorangestellten Sternchen (*) übergeben wird.
Das Entpacken einer Parameterliste funktioniert nicht nur im Zusammenhang mit einer Funktion, die
beliebig viele Parameter erwartet.
Analog zum Entpacken eines Tupels zu einer Liste von Positionsparametern kann ein Dictionary zu einer
Liste von Schlüsselwortparametern entpackt werden (Übergabe mit zwei vorangestellten Sternchen (**)).
Zusätzlich gibt es seit Python 3.5 die Möglichkeit, auch beim Erzeugen von sequenziellen Datentypen,
Mengen und Dictionarys auf Packing bzw. Unpacking zurückzugreifen:
A = [1, 2, 3]
B = [3, 4, 5]
C = [1, *A, *B] => [1, 1, 2, 3, 3, 4, 5]
Sogenannte Seiteneffekte (engl. side effects) können immer dann auftreten, wenn eine Instanz eines
mutablen Datentyps, also zum Beispiel einer Liste oder eines Dictionarys, als Funktionsparameter
übergeben werden. In Python werden bei einem Funktionsaufruf keine Kopien (Prinzip Call by Value) der
als Paramter übergebenen Instanzen erzeugt, sondern es wird funktionsintern mit Referenzen auf die Argumente
gearbeitet (Prinzip Call by Reference).
Wenn eine Funktion nicht nur lesend auf ene Instanz eines veränderlichen Datentyps zugreifen muss und
Seiteneffekte nicht ausdrücklich erwünscht sind, sollte innerhalb der Funktion oder bei der Parameterübergabe
eine Kopie der Instanz erzeugt werden.
Eine Instanz, die als Default-Wert genutzt wird, wird nur einmalig und nicht bei jedem Funktionsaufruf
neu erzeugt.
In manchen Situationen ist es sinnvoll, eine Funktion über ihren lokalen Namensraum hinaus wirken zu lassen.
Referenzen und Instanzen, welche im Kontext einer Funktion, also im Funktionskörper, erzeugt werden,
haben nur unmittelbar in der Funktion selbst Gültigkeit. Sie existieren im lokalen Namensraum.
Im Gegensatz dazu existieren Referenzen des Hauptprogramms im globalen Namensraum.
Begrifflich wird auch zwischen globalen Referenzen und lokalen Referenzen unterschieden.
Im lokalen Namensraum einer Funktionskörpers kann jederzeit lesend auf eine globale Referenz zugegriffen
werden, solange kein lokale Referenz gleichen Namens existiert. Sobald versucht wird, schreibend auf eine
globale Referenz zuzugreifen, wird stattdessen eine entsprechende lokale Referenz erzeugt.
Eine Funktion kann mithilfe der global-Anweisung schreibend auf eine globale Referenz zugreifen.
Dazu muss im Funktionskörper das Sclüsselwort global geschrieben werden, gefolgt von einer oder mehreren
globalen Referenzen.
Es ist möglich, lokale Funktionen zu definieren. Das sind Funktionen, die im lokalen Namensraum
einer anderen Funktion angelegt werden und nur dort gültig sind.
Bei verschachtelten Funktionen kann mittels dem Schlüsselwort nonlocal auf Referenzen übergeordneter
Namensräume zugegriffen werden. Allgemein funktioniert nonlocal bei tieferen Funktions-
verschachtelungen so, dass es in der Hierarchie der Namensräume aufsteigt und die erste Referenz mit dem
angegebenen Namen in den Namensraum des nonlocal-Schlüsselworts einbindet.
Mithilfe des Schlüsselwortes lambda kann eine kleine Funktion erstellt werden. Auf das Schlüsselwort
lambda folgen eine Parameterliste und ein Doppelpunkt. Hinter dem Doppelpunkt muss ein beliebiger
arithmetischer oder logischer Ausdruck stehen, dessen Ergebnis von der anonymen Funktion zurückgegeben wird:
Beispiel: s = lambda x: -x
Die Elemente einer Funktionsschnittstelle, also die Funktionsparameter und der Rückgabewert, lassen sich
mit Anmerkungen, sogenannte Annotationen, versehen:
def strmult(s: str, n: int) -> str:
return s * n
Annotationen kann man über das Attribut __annotations__ auslesen:
strmult.__annotations__ => {'s': <class 'str'>, 'n': <class 'int'>, 'return': <class 'str'>}
Mit Function Annotations kann beispielsweise eine Typüberprüfung an der Funktionsschnittstelle
durchgeführt werden.
Rekursive Funktionen sind Funktionen, die sich selbst aufrufen. Die aufgerufene Funktion ruft sich so
lange selbst auf, bis eine Abbruchbedingung diese sonst endlose Rekursion beendet. Die Anzahl der
verschachtelten Funktionsaufrufe wird Rekursionstiefe genannt und ist von der Laufzeitumgebung auf
einen bestimmten Wert begrenzt.