Funktionen#

Funktionsdefinition und Funktionsaufruf#

Alle höheren Programmiersprachen erlauben die Definition von Funktionen (oder Prozeduren), um sich ständig wiederholenden Code nur einmal schreiben zu müssen und komplexe Programme zu strukturieren.

Funktionen werden in Python mit dem Schlüsselwort def definiert. Sie haben einen funktionsnamen und können mehrere Argumente als Eingabe in einer Klammer haben. Die Deklaration der Funktion wird mit : beendet. Der Körper der Funktion, also der Teil, welcher beim Aufrufen der Funktion ausgeführt werden soll, muss immer eingerückt werden.

def funktionsname(argument1, argument2):
    # Funktionskörper
    print("Der Datentyp von Argument 1 ist "+str(type(argument1)))
    print("Der Datentyp von Argument 2 ist "+str(type(argument2)))

Hierbei müssen alle Teile der Funktion gleich eingerückt werden. Der folgende Code ist z.B. syntaktisch falsch

def funktionsname(argument1, argument):
    # Funktionskörper
    print("Der Datentyp von Argument 1 ist "+str(type(argument1)))
        print("Der Datentyp von Argument 2 ist "+str(type(argument2)))
  Cell In[2], line 4
    print("Der Datentyp von Argument 2 ist "+str(type(argument2)))
    ^
IndentationError: unexpected indent

Beim Aufruf der Funktion durch den funktionsname(wert1, wert2) müssen die Argumente mit Eingabewerten belegt werden. Die Argumente in Python werden wie andere Variablen dynamisch typisiert (Wir wissen also nicht unbedingt welchen Datentyp sie später haben werden. Das ist eine typische Fehlerquelle).

funktionsname("wert1", 2)
Der Datentyp von Argument 1 ist <class 'str'>
Der Datentyp von Argument 2 ist <class 'int'>

Das entscheidende ist, dass die Argumente ihre Werte ändern können.

funktionsname("anderer wert ", "noch ein anderer")
Der Datentyp von Argument 1 ist <class 'str'>
Der Datentyp von Argument 2 ist <class 'str'>

Ergebnisrückgabe#

Die Anweisung return wird in Funktionen benutzt, um die Ausführung einer Funktion zu beenden und den zugewiesenen Wert(e) als Ergebnis der Funktion zurückzugeben.

def funktion_mit_einer_ausgabe():
    return "Ausgabewert"
    print("Dieser Teil wird nicht ausgeführt")
    return "Anderer Ausgabewert"
ergebnis = funktion_mit_einer_ausgabe()
ergebnis
'Ausgabewert'

Wir sehen, dass das Ergebnis Ausgabewert ist und die print() Funktion nicht aufgerufen worden ist.

Es können mehrere Ausgabewerte mit return zurückgegeben werden.

def funktion_mit_zwei_ausgaben():
    return "Ausgabewert1", "Ausgabewert2"
ergebnis = funktion_mit_zwei_ausgaben()
ergebnis
('Ausgabewert1', 'Ausgabewert2')

Das Ergebnis von Funktionen mit mehreren Rückgaben ist ein Tuple.

type(ergebnis)
tuple

Auf die einzelnen Werte im Tuple kann durch den Index zugegriffen werden. Zur Erinnerung der Index einer Liste oder eines Tuples startet mit 0.

ergebnis[0]
'Ausgabewert1'

Das Tuple kann allerdings auch durch Mehrfachzuweisung verhindert werden. Bei einer Mehrfachzuweisung listet man mehrere durch Komma getrennte Variablen links von der Zuweisung auf.

ergebnis1, ergebnis2 = funktion_mit_zwei_ausgaben()
print(ergebnis1)
print(ergebnis2)
print(type(ergebnis1))
print(type(ergebnis2))
Ausgabewert1
Ausgabewert2
<class 'str'>
<class 'str'>

Variablengültigkeit#

Variablen innerhalb von Funktionen sind nicht global gültig. So sind die Variablen der Argumente nur innerhalb der Funktion gültig. Auch neue Variablen, die in der Funktion definiert werden, sind nicht außerhalb der Funktion gültig. So sind in der folgenden Funktion:

def meine_funktion(argument):
    interne_variable = "geheim"
    print("Der Wert von argument innerhalb der Funktion ist "+str(argument))
    print("Der Wert von intern innerhalb der Funktion ist "+str(interne_variable))

die Werte von argument und intern innerhalb der Funktion definiert und werden im ´print()´ Statement ausgegeben.

meine_funktion("argument_wert")
Der Wert von argument innerhalb der Funktion ist argument_wert
Der Wert von intern innerhalb der Funktion ist geheim

Die Variablen argument und interne_variable sind nach dem Ausführen der Funktion allerdings nicht global verfügbar.

print(argument)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[14], line 1
----> 1 print(argument)

NameError: name 'argument' is not defined
print(interne_variable)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[15], line 1
----> 1 print(interne_variable)

NameError: name 'interne_variable' is not defined

Die erlaubt es auch Variablennamen außerhalb der Funktion zu definieren, welche innerhalb der Funktion einen anderen Wert haben können. So bleibt der Wert von argument unverändert.

argument = 6 # orginalwert
print("Der Wert von argument vor der Funktion ist "+str(argument))
meine_funktion(4)
print("Der Wert von argument nach der Funktion ist immer noch "+str(argument))
Der Wert von argument vor der Funktion ist 6
Der Wert von argument innerhalb der Funktion ist 4
Der Wert von intern innerhalb der Funktion ist geheim
Der Wert von argument nach der Funktion ist immer noch 6

Veränderte und unveränderte Argumente#

Grundsätzlich werden Modifikationen an Argumenten primitiver Datentypen innerhalb der Funktion nicht übernommen (pass-by-value). So, lässt sich innerhalb der Funktion auch Argumenten neue Werte zuweisen.

def meine_funktion(argument):
    print("Der Wert von argument am Anfang der Funktion ist "+str(argument))
    argument = 3
    print("Der Wert von argument am Ende der Funktion ist "+str(argument))

argument = 6 # orginalwert
print("Der Wert von argument vor der Funktion ist "+str(argument))
meine_funktion(argument)
print("Der Wert von argument nach der Funktion ist immer noch "+str(argument))
Der Wert von argument vor der Funktion ist 6
Der Wert von argument am Anfang der Funktion ist 6
Der Wert von argument am Ende der Funktion ist 3
Der Wert von argument nach der Funktion ist immer noch 6

Das funktioniert auch bei komplexen Datentypen, wie list, set, dict, sofern sie komplett neu zugewiesen werden.

def meine_funktion(argument):
    print("Der Wert von argument am Anfang der Funktion ist "+str(argument))
    argument = [3]
    print("Der Wert von argument am Ende der Funktion ist "+str(argument))

argument = [6] # orginalwert
print("Der Wert von argument vor der Funktion ist "+str(argument))
meine_funktion(argument)
print("Der Wert von argument nach der Funktion ist immer noch "+str(argument))
Der Wert von argument vor der Funktion ist [6]
Der Wert von argument am Anfang der Funktion ist [6]
Der Wert von argument am Ende der Funktion ist [3]
Der Wert von argument nach der Funktion ist immer noch [6]

Werden sie allerdings nur modifiziert (pass-by-reference), so sind diese Änderungen auch global.

def meine_funktion(argument):
    print("Der Wert von argument am Anfang der Funktion ist "+str(argument))
    argument.append(3) # Wir fügen 3 der liste hinzu
    print("Der Wert von argument am Ende der Funktion ist "+str(argument))

argument = [6] # orginalwert
print("Der Wert von argument vor der Funktion ist "+str(argument))
meine_funktion(argument)
print("Der Wert von argument nach der Funktion ist auf einmal "+str(argument))
Der Wert von argument vor der Funktion ist [6]
Der Wert von argument am Anfang der Funktion ist [6]
Der Wert von argument am Ende der Funktion ist [6, 3]
Der Wert von argument nach der Funktion ist auf einmal [6, 3]

Warning

Das kann sehr schnell zu Fehlern führen, wenn man unbeabsichtigt globale Datenstrukturen verändert.