4. Funktionen
Eigene Funktionen in Python definieren
Sie kennen bereits die Funktionen print sowie t.forward und haben diese auch schon mehrmals selbst verwendet. In diesem Kapitel werden Sie lernen, wie Sie eigene Funktionen in Python definieren und schliesslich sinnvoll verwenden können. Funktionen helfen enorm dabei, Programme leserlicher, kürzer, effizienter und wartbarer zu machen. Funktionen sind deshalb aus modernen Programmen kaum wegzudenken.
Tipps für das Schreiben von Funktionen:
- Der Name einer Funktion sollte selbsterklärend und beschreibend sein. Im Idealfall lässt der Name der Funktion schon viel über ihren Effekt erahnen. Beispielsweise ist der Funktionsname
quadratviel beschreibender als ein nichtssagender Name wie zum Beispielf. - Etwas komplexere Tätigkeiten sollten jeweils als eine Funktion definiert werden und damit einen Namen erhalten. So kann beispielsweise das Zeichnen eines Quadrats in einer Funktion
quadratdefiniert werden, während das Zeichnen einer Blume in der Funktionquadrat_blumedefiniert wird. Diese Funktion kann dann wiederum die Funktionquadrataufrufen.
Parameter
Stellen Sie sich vor, Sie wollen drei unterschiedlich grosse Quadrate zeichnen. Sie könnten folgendermassen vorgehen:
# File: squares_noparams.py
import turtle as t
def quadrat_50():
for _ in range(4):
t.fd(50)
t.rt(90)
def quadrat_100():
for _ in range(4):
t.fd(100)
t.rt(90)
def quadrat_150():
for _ in range(4):
t.fd(150)
t.rt(90)
quadrat_50()
quadrat_100()
quadrat_150()Das ging gerade noch! Was jedoch, wenn Sie 20 unterschiedlich grosse Quadrate zeichnen wollen? Brauchen Sie dann 20 Definitionen? Zum Glück nicht, wie Beispiel Abschnitt zeigt.
Funktionen können mehrere (oder auch gar keine) Parameter haben. Ersteres ist besonders nützlich, wenn Sie eine Funktion schreiben wollen, die mehrere Werte benötigt, um ihre Aufgabe zu erfüllen. Zum Beispiel könnte eine Funktion, die ein Vieleck zeichnet, sowohl die Anzahl der Ecken als auch die Farbe des Vielecks benötigen.
Lebensdauer (*scope
) einer Variablen Im Code aus Abschnitt wird bei jedem Aufruf* der Definition quadrat eine neue Variable laenge erstellt, welche nur innerhalb der Funktion existiert und welche jedes Mal einen anderen Wert hat. Den Wert erhält die Variable zum Zeitpunkt des Aufrufs der Funktion, also auf den Zeilen 8, 9 und 10!
Die Variable laenge existiert also nur innerhalb der Definition quadrat. Wenn wir nach Zeile 6 im Hauptprogramm (nicht eingerückt) den Befehl print(laenge) eingeben würden, würden wir eine Fehlermeldung erhalten, da es die Variable nicht mehr gibt. Parameter sind also immer lokale Variablen, ebenso wie Variablen, welche wir innerhalb von Funktionen erstellen. Diese Variablen “sterben” nach Ausführung der Definition, daher spricht man auch von der Lebensdauer einer Variable, bzw. von deren Reichweite (Englisch: scope).
Variablen, welche im Hauptprogramm (nicht eingerückt) erstellt werden, sind sogenannte globale Variablen.
Werte zurückgeben mit return
Einzelne Funktionen
Wie Sie bereits wissen, können Definitionen mit Kochrezepten verglichen werden: Sie beschreiben einen Ablauf, ohne diesen auszuführen. Damit der Code einer Funktion ausgeführt wird, müssen Sie die Definition aufrufen: In Abschnitt wurde dies beispielsweise mit farb_vieleck(3, "red") gemacht. Erst aufgrund dieser Zeile wurde etwas gezeichnet!
Dies kann nützlich sein, wenn sie eine Aufgabe mehrmals und in unterschiedlichen Varianten ausführen wollen, wie beispielsweise in Abschnitt.
Eine wichtige Limitation von Definitionen war bisher, dass Sie zwar Dinge berechnen und im Terminal ausgeben konnten, allerdings verschwinden alle Parameter und lokalen Variablen nach der Ausführung einer Funktion. Dies bedeutet, dass alle Variablen, die wir je in einer Definition erstellt haben, nur in dieser Definition “lebten”. Wir konnten jedoch nicht mehr auf Parameter oder lokale Variablen zugreifen, nachdem die Funktion beendet wurde.
Funktionen können jedoch auch Werte an das Hauptprogramm zurückgeben: In diesem Kapitel lernen wir, wie Funktionen, ähnlich wie “Sous-Chefs” (Hilfs-Köche) in einer komplexen Küche Zutaten (Parameter) entgegennehmen und Resultate an andere “Sous-Chefs” (Funktionen) via das Hauptprogramm weitergeben werden können.
Eine Funktion kann man sich vorstellen wie ein Kochrezept, das einige Zutaten entgegennimmt und ein Resultat (Gericht) zurückgibt. Die Zutaten, oder “Inputs”, werden dabei häufig als “Parameter” bezeichnet, währenddem das fertige Gericht, oder “Resultat” häufig als “return-Wert” bezeichnet wird. Diese Idee ist in Abschnitt veranschaulicht.
Mehrere Funktionen
Wie Sie in Abschnitt gesehen haben, ist ein return in vielen Fällen nicht notwendig, ein einfaches print reicht in vielen Fällen aus. Wozu kann ein return eigentlich nützlich sein? Wenn Sie Code schreiben, wird dieser oftmals schnell komplizierter. Somit kann es hilfreich sein, die einzelnen Schritte in Unter-Programme aufzuteilen. Dies erleichtert zudem die Modularisierung und Wiederverwendbarkeit von Code: Beispielsweise könnte eine Funktion, die das Maximum einer Liste berechnet, an verschiedenen Orten in einem längeren Programm mehrmals zum Einsatz kommen.
Zum Vergleich: stellen Sie sich vor, Sie arbeiten in einer edlen Michelin-Sterne-Küche an einem raffinierten Gericht, in das viele Arbeitsschritte involviert sind. Häufig müssen in solchen Restaurants bis zu 200 Schritte pro Gericht ausgeführt werden. Daher könnte es sinnvoll sein, einzelne Aufgaben, wie beispielsweise die Herstellung der Saucen, an Ihre Sous-Chefs zu delegieren, und eine Person zu bestimmen, die das ganze Gericht zusammenfügt. Häufig werden Funktionen genau mit solchen komplexen Aufgaben im Hinterkopf geschrieben. Diese Idee ist in Abschnitt illustriert.
In Abschnitt haben wir eine Funktion a1, die zwei Parameter entgegennimmt (x1 und x2). Mit diesen Parametern macht sie etwas (z.B. die Summe berechnen, ein Quadrat zeichnen oder irgend eine sonstige Aufgabe) und gibt danach einen neuen, berechneten Wert a1 zurück. Dieser kann im Hauptprogramm abgespeichert und an andere Funktionen weitergegeben werden, beispielsweise an die Funktion a3.
Mit folgendem Code können wir die Turtle eine Spirale aus mehreren Vielecken zeichnen lassen:
# File: spirale_kreis.py
import turtle as t
# don't show turtle moving
t.tracer(False)
def vieleck(umfang, ecken):
for _ in range(ecken):
t.fd(umfang / ecken)
t.rt(360 / ecken)
def vieleck_muster(umfang, ecken):
for _ in range(60):
vieleck(umfang, ecken)
t.rt(6)
umfang -= 10
vieleck_muster(600, 36)
t.done()