Funktionen#

Midjourney: Functional Lines, ref. C.E.B. Reas

A function of good software is to make the complex appear simple.

— Grady Booch

Folien/PDF#

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]
⚠️ Achtung: Das kann sehr schnell zu Fehlern führen, wenn man unbeabsichtigt globale Datenstrukturen verändert.

Quiz#

shuffleQuestions: true shuffleAnswers: true ### Wozu dienen Funktionen in Python? - [x] Um wiederverwendbaren Code zu strukturieren - [x] Um Programme übersichtlicher zu machen - [ ] Um den Code schneller zu machen - [ ] Um Datenbanken zu erstellen ### Wie beginnt eine Funktionsdefinition in Python? - [x] Mit dem Schlüsselwort `def` - [ ] Mit `function` - [ ] Mit `define()` - [ ] Mit `func` ### Was passiert, wenn der Funktionskörper nicht richtig eingerückt ist? - [x] Es gibt einen Syntaxfehler - [ ] Die Funktion wird ignoriert - [ ] Die Funktion wird als globale Funktion gespeichert - [ ] Python rückt den Code automatisch ein ### Was macht `return` in einer Funktion? - [x] Beendet die Funktion und gibt einen Wert zurück - [ ] Gibt automatisch alle Argumente aus - [ ] Wiederholt die Funktion - [ ] Überspringt den Rest des Codes ### Was passiert, wenn mehrere Werte mit `return` zurückgegeben werden? - [x] Es wird ein Tuple zurückgegeben - [ ] Nur der erste Wert wird zurückgegeben - [ ] Es entsteht ein Fehler - [ ] Alle Werte werden automatisch ausgedruckt ### Wo sind Variablen gültig, die innerhalb einer Funktion definiert wurden? - [x] Nur innerhalb der Funktion - [ ] Im gesamten Programm - [ ] Innerhalb von Schleifen - [ ] Im gesamten Modul ### Was passiert mit einer Variable `x`, die in einer Funktion definiert ist? - [x] Sie existiert nur während der Funktionsausführung - [ ] Sie überschreibt globale Variablen automatisch - [ ] Sie wird zu einer globalen Konstante - [ ] Sie bleibt im Speicher bis das Programm beendet ist ### Was passiert mit primitiven Datentypen, wenn sie einer Funktion übergeben und dort verändert werden? - [x] Die Änderung bleibt lokal innerhalb der Funktion - [ ] Die ursprüngliche Variable wird immer überschrieben - [ ] Python speichert die Änderung automatisch global - [ ] Die Funktion gibt automatisch eine Kopie zurück ### Was passiert, wenn man eine Liste in einer Funktion **modifiziert**, aber nicht neu zuweist? - [x] Die Änderung wirkt sich auch außerhalb der Funktion aus - [ ] Die Liste wird automatisch kopiert - [ ] Die Funktion erzeugt eine neue Liste - [ ] Es entsteht ein Fehler ### Wie verhält sich eine Liste, die in einer Funktion **neu zugewiesen** wird? - [x] Die globale Liste bleibt unverändert - [ ] Die globale Liste wird überschrieben - [ ] Sie kann nicht innerhalb einer Funktion verwendet werden - [ ] Python blockiert diese Zuweisung ### Wie läuft ein Python-Programm grundsätzlich ab? - [x] Zeile für Zeile, von oben nach unten - [ ] Zufällig, abhängig vom Interpreter - [ ] Erst am Ende, dann rückwärts - [ ] Von Funktionen zu Hauptprogramm ### Was passiert, wenn eine Funktion definiert, aber nicht aufgerufen wird? - [x] Der Code in der Funktion wird übersprungen - [ ] Die Funktion wird trotzdem automatisch ausgeführt - [ ] Der Code wird nur beim nächsten Neustart ausgeführt - [ ] Python zeigt eine Warnung ### Was passiert beim Funktionsaufruf? - [x] Der Funktionscode wird an dieser Stelle ausgeführt - [ ] Nur die Rückgabe wird berechnet - [ ] Nur die letzte Zeile der Funktion wird ausgeführt - [ ] Python pausiert das Hauptprogramm ### Was ist eine rekursive Funktion? - [x] Eine Funktion, die sich selbst aufruft - [ ] Eine Funktion, die nur einmal aufgerufen werden darf - [ ] Eine Funktion ohne Parameter - [ ] Eine spezielle Schleifenfunktion in Python ### Welcher Fehler steckt in diesem Beispiel? ```python def rekursive_funktion(): rekursive_funktion() ``` - [x] Es fehlt die Abbruchbedingung, dadurch entsteht eine Endlosschleife - [ ] Der Funktionsname ist ungültig - [ ] Python erlaubt keine Selbstaufrufe - [ ] Die Funktion muss einen Parameter haben ### Sortiere die folgenden Zeilen, um eine einfache rekursive Funktion korrekt zu implementieren: ```python n = 3 ``` 1. `def count_down(n):` 2. ` if n <= 0:` 3. ` print("Fertig!")` 4. ` else:` 5. ` print(n)` 6. ` count_down(n - 1)`