Dies ist eine alte Version des Dokuments!
Wiederhole dich nicht! (Funktionen)
Während wir natürlich wollen, dass bestimmte Teile eines Programmes wiederholt ausgeführt werden und das mit Hilfe der Schleife inzwischen auch können, wollen wir nicht, dass man das gleiche Verhalten in einem Programm mehrfach programmiert. Gute Programme erfüllen das sog. „DRY“-Prinzip (=Don’t Repeat Yourself), wonach alles, was gleich funktioniert, nur einmal programmiert werden soll. Vielleicht ist dir schon aufgefallen, dass wir das bisher nicht können. Wenn man von einem Ort wieder zurück gehen möchte, dann muss man die gleiche Beschreibung noch einmal programmieren … und endloses Hin- und Herlaufen können wir bislang gar nicht realisieren.
Das Problem können wir mit Hilfe von selbstdefinierten Funktionen lösen. Das sind eigene „Anweisungen“, die man genau wie die vordefinierten Funktionen in einem Programm beliebig oft aufrufen kann. Das folgende Beispiel zeigt wie das funktioniert.
- funktionen.py
- def waldlichtung():
- gute_antwort = False
- while not gute_antwort:
- print("Waldlichtung")
- print("Du befindest dich auf einer kleinen Lichtung im Wald. Hohe Bäume umringen den Platz, ihr Blätterdach lässt nur vereinzelte Sonnenstrahlen hindurch. Ein schmaler Pfad führt nach Norden und ein anderer nach Osten. Der Boden ist weich, mit Moos bedeckt, und du meinst, in der Ferne das Plätschern von Wasser zu hören.")
- wahl = input("Wohin soll es gehen? (n=Norden, o=Osten) ")
- if wahl == "n":
- gute_antwort = True
- flussufer()
- elif wahl == "o":
- gute_antwort = True
- verlasseneHuette()
- else:
- dunklerWald()
- def flussufer():
- gute_antwort = False
- while not gute_antwort:
- print("Flussufer")
- print("Der Pfad mündet an ein glitzerndes Flussufer. Das Wasser ist klar und fließt ruhig dahin, doch weiter auf der anderen Seite siehst du dichten Wald. Ein alter Holzsteg ragt ein Stück in den Fluss – instabil, aber vielleicht noch nutzbar. Zurück kannst du Süden gehen, zurück zur Waldlichtung.")
- wahl = input("Wohin soll es gehen? (s=Süden) ")
- if wahl == "s":
- gute_antwort = True
- waldlichtung()
- else:
- dunklerWald()
- def verlasseneHuette():
- gute_antwort = False
- while not gute_antwort:
- print("Verlassene Hütte")
- print("Ein schmaler Weg führt dich zu einer kleinen, verwitterten Hütte. Die Fenster sind blind vor Staub, die Tür steht einen Spalt offen. Drinnen scheint es dunkel, aber du meinst, einen schwachen Geruch von Rauch wahrzunehmen – vielleicht war hier kürzlich jemand. Du kannst zurück nach Westen, zur Waldlichtung.")
- wahl = input("Wohin soll es gehen? (w=Westen) ")
- if wahl == "w":
- gute_antwort = True
- waldlichtung()
- else:
- dunklerWald()
- def dunklerWald():
- print("Dunkler Wald")
- print("Du verlässt den schmalen Pfad und schlägst dich durchs Unterholz. Schon nach wenigen Schritten verdunkelt sich das Licht, und die Luft wird kälter. Der Wald wirkt hier älter, dichter – fast lebendig. Zwischen den knorrigen Wurzeln scheint Nebel aufzusteigen, der lautlos über den Boden kriecht. Schnell kehrst du um, bevor du den Weg zurück nicht mehr findest.")
- waldlichtung()
Führe das Programm mit Thonny mehrmals aus und mache unterschiedliche Eingaben. Fasse zusammen, was Du beobachtest.
Möglicherweise ist dir aufgefallen, dass die Programmausführung nun nicht mehr endet, weil man immer zwischen den drei bzw. vier Orten hin- und herläuft, aber dazu später. Erstmal ist wichtig, dass das Programm nun anders strukturiert ist. Es gibt für jeden Ort eine eigene Funktion. Diese wird mit dem „Schlüsselwort“ def eingeleitet, dann folgt der Name der Funktion und schließlich Klammern und ein Doppelpunkt. Die Klammern, das weißt du schon, stehen für die Parameter. Unsere Funktionen haben aktuell keine Parameter, also sind die Klammern leer – sie dürfen aber nicht fehlen. Der Doppelpunkt schließt den „Funktionskopf“ ab. Der folgende, eingerückte Block von Anweisungen bildet den „Funktionsrumpf“. Er wird immer ausgeführt, wenn irgendwo im Programm diese Funktion aufgerufen wird.
Der Funktionsaufruf in Zeile 44 ist notwendig, damit das Programm irgendwo startet. Solange eine Funktionsdefinition nur so im Programmtext steht, passiert gar nichts. Der Interpreter würde dann feststellen „Aha, es gibt also die Funktion …“, aber ausgeführt wird sie erst, wenn irgendwo ein Funktionsaufruf steht. Dass der Funktionsaufruf am Ende des Programmes steht, liegt daran, dass vorher die Funktionen noch nicht bekannt sind. Der Interpreter arbeitet immer von oben nach unten. Die Funktionsdefinitionen werden also erst „zur Kenntnis genommen“, danach kann man sie aufrufen. Der Python-Interpreter prüft dabei erst zur Laufzeit, also wenn eine Anweisung konkret ausgeführt wird, ob es die Funktion auch wirklich gibt. Deshalb kann die Funktion flussufer() in der Funktion waldlichtung() aufgerufen werden, obwohl waldlichtung() vor flussufer() im Programmtext steht. Zu dem Zeitpunkt, wo flussufer() aufgerufen wird, hat der Interpreter die Funktionsdefinition schon einmal eingelesen.
Ändere das Programm so, dass der Funktionsaufruf von waldlichtung() nicht am Ende des Programmtextes steht, sondern hinter der Definition von flussufer() und vor der Definition von dunlerWald() (Zeile 28). Starte das Programm, bewege dich ein wenig durch die Landschaft und beobachte, was passiert. Erkläre die Beobachtung.
In jedem der drei „richtigen“ Orte gibt es nun eine Ortsbeschreibung und dann eine anpasste Eingabe nach dem bekannten Muster. Dabei wird jetzt aber in den Zweigen der Fallunterscheidung nur mehr die jeweils passende Funktion aufgerufen. Damit kannst du jetzt auch ein komplexeres „Dungeon“ aufbauen.
Ändere die Programmierung so, dass man das Programm an irgendeinem Ort beenden kann.
Schreibe nun dein Textadventure so um, dass du Funktionen verwendest.
Vielleicht ist Dir aufgefallen, dass es eine weitere „Chance“ gibt, wiederkehrende Programmierung in einer eigenen Funktion auszulagern? Gemeint ist die Eingabe, die auch immer zumindest ähnlich ist. Wenn du magst, kannst du gerne jetzt schon versuchen, eine eigene „Eingabe-Funktion“ zu definieren. Wir kommen sonst später darauf zurück.
Link zum Python-Handbuch: https://openbook.rheinwerk-verlag.de/python/19_001.html#u19.1
Nächste Lektion: Ich packe in meinen Rucksack …