Einmal schreiben, oft benutzen
Eine Funktion ist wie ein kleines Programm innerhalb eines größeren. Sie fasst einen Block von Code zusammen, der eine bestimmte Aufgabe erfüllt. So zerlegst du dein Programm in kleinere, wiederverwendbare Teile: Du schreibst weniger, und das Ergebnis ist leichter zu lesen und zu pflegen.

Hast du eine Funktion geschrieben, kannst du sie benutzen wie einen „normalen“ Befehl.
In Python erstellst du eine Funktion, indem du definierst, wie sie heißt und was sie tun soll. Das Schlüsselwort dafür lautet def. Es steht am Anfang jeder Funktionsdefinition.
Eine Funktion ohne Parameter
Die folgende Funktion gibt mit einer Schleife die Zahlen von 1 bis 10 aus. Anschließend wird sie aufgerufen – ohne den Aufruf geschieht nichts.
def einsBisZehn(): # "def", dann der Name der Funktion.
# Zu den runden Klammern später mehr.
print("Die Zahlen von 1 bis 10") # Dieser Teil läuft erst beim Aufruf.
i = 1 # Er ist um eine Ebene eingerückt.
while i < 11:
print(i)
i = i + 1
einsBisZehn() # Aufruf wie bei einem normalen Befehl.
# Beachte die Groß- und Kleinschreibung.
Die Klammern gehören beim Aufruf dazu. Schreibst du nur
einsBisZehnohne Klammern, meinst du die Funktion selbst und rufst sie nicht auf – es passiert dann nichts.
Python liest den Block unter def zunächst nur und merkt ihn sich. Ausgeführt wird er erst beim Aufruf. Dann springt das Programm in die Funktion, arbeitet sie von oben nach unten ab und macht in der Zeile nach dem Aufruf weiter. Rufst du einsBisZehn() zweimal auf, läuft sie zweimal.
Deshalb muss die Definition im Programm vor dem ersten Aufruf stehen. Steht der Aufruf davor, kennt Python den Namen noch nicht:
Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'einsBisZehn' isn't defined
Dieselbe Meldung erscheint, wenn du dich beim Namen vertippst.
Parameter
Aus der Mathematik kennst du Parameter vielleicht schon. Betrachtest du eine Funktion f(x), so ist x ein Parameter: ein Wert, der später eingesetzt und mit dem weitergerechnet wird.
In der Programmierung erfüllen Parameter dieselbe Aufgabe. Über sie übergibst du einer Funktion einen oder mehrere Werte, mit denen sie arbeitet.
def addiereZweiZahlen(s1, s2): summe = s1 + s2 print(summe)
Diese Funktion heißt „addiereZweiZahlen“. Sie erwartet zwei Werte, die innerhalb der Funktion „s1“ und „s2“ heißen, addiert sie und gibt das Ergebnis aus.
Beim Aufruf schreibst du die Werte in die Klammern. Sie werden der Reihe nach übernommen: Die 12 landet in „s1“, die 17 in „s2“.
def addiereZweiZahlen(s1, s2): summe = s1 + s2 print(summe) addiereZweiZahlen(12, 17)
Die Anzahl der Werte muss zur Definition passen. Schreibst du nur addiereZweiZahlen(12), erscheint:
Traceback (most recent call last): File "<stdin>", line 5, in <module> TypeError: function takes 2 positional arguments but 1 were given
Die Funktion nimmt also zwei Werte, bekommen hat sie einen. Beim Aufruf müssen keine festen Zahlen stehen. Variablen gehen genauso:
def addiereZweiZahlen(s1, s2): summe = s1 + s2 print(summe) a = 4 b = 6 addiereZweiZahlen(a, b) # Der Wert von a landet in s1, der Wert von b in s2 addiereZweiZahlen(a, 100) # Variablen und feste Zahlen dürfen sich mischen
Rückgabewerte
Die Funktion oben gibt ihr Ergebnis selbst aus. Oft willst du mit dem Ergebnis aber weiterarbeiten. Dann lässt du es die Funktion mit dem Schlüsselwort return zurückgeben.
Im folgenden Beispiel wird „addiereZweiZahlen“ mit den Zahlen 3 und 5 aufgerufen. Die Funktion addiert sie und gibt das Ergebnis 8 zurück. Es wird in der Variablen „ergebnis“ gespeichert und erst danach ausgegeben.
def addiereZweiZahlen(s1, s2): summe = s1 + s2 return summe ergebnis = addiereZweiZahlen(3, 5) print(ergebnis)
return beendet die Funktion sofort. Zeilen, die dahinter stehen, werden nicht mehr ausgeführt.
Das kannst du nutzen. Die folgende Funktion liefert die größere von zwei Zahlen:
def groessere(a, b):
if a > b: # Ist a größer, endet die Funktion hier.
return a
return b # Hier geht es nur weiter, wenn a nicht größer ist.
print(groessere(4, 9)) # Ausgabe: 9
print(groessere(12, 5)) # Ausgabe: 12
Den Rückgabewert kannst du überall einsetzen, wo auch ein normaler Wert stehen darf, zum Beispiel in einer Rechnung: print(addiereZweiZahlen(3, 5) * 2) gibt 16 aus.
Verwechsle print und return nicht. print zeigt einen Wert in der Konsole an, das Programm kann danach aber nichts mehr mit ihm anfangen. Gibt eine Funktion nichts mit return zurück, liefert sie den Sonderwert None („nichts“). Benutzt du die Fassung mit print aus dem vorigen Abschnitt in ergebnis = addiereZweiZahlen(3, 5), steht in ergebnis deshalb None.
Funktionen helfen dir also, dein Programm zu ordnen und verständlich zu halten. Und sie sparen Zeit, weil du denselben Code nicht immer wieder neu schreiben musst.
Übung: das Quadrat
Schreibe eine Funktion quadrat(zahl), die das Quadrat einer Zahl zurückgibt. Berechne damit 3 mal 3 plus 4 mal 4.
Funktionen auf dem Display
Besonders nützlich sind Funktionen beim Zeichnen. Die folgende Funktion zeichnet eine Kiste an eine beliebige Stelle. Einmal geschrieben, ruft eine Schleife sie gleich fünfmal auf.
from picoboy import PicoBoy pb = PicoBoy() # Den Teil oberhalb dieser Zeile nicht verändern def kiste(x, y, groesse): # x, y und groesse sind Parameter pb.rect(x, y, groesse, groesse, 1) # Umriss der Kiste pb.line(x, y, x + groesse - 1, y + groesse - 1, 1) # eine Diagonale pb.line(x, y + groesse - 1, x + groesse - 1, y, 1) # die andere Diagonale pb.fill(0) for i in range(0, 5): # fünf Kisten nebeneinander kiste(i * 24 + 6, 22, 20) pb.show()
Beim Aufruf kiste(i * 24 + 6, 22, 20) setzt Python die drei Werte für x, y und groesse ein. Die x-Position ist also nacheinander 6, 30, 54, 78 und 102. Jede Kiste ist 20 Pixel breit, also bleiben dazwischen 4 Pixel frei.
Die - 1 in den Diagonalen hat denselben Grund wie beim Haus vom Nikolaus: Eine Kiste der Größe 20, die bei x beginnt, endet bei x + 19. Ohne die - 1 ragten die Diagonalen ein Pixel über den Rand hinaus.
Übung: wachsende Kisten
Ändere den Aufruf in kiste(i * 24 + 6, 22, 8 + i * 3). Die Funktion selbst bleibt, wie sie ist, und trotzdem wird jede Kiste größer als die vorige. Dafür sind Parameter da.
Globale Variablen
Variablen, die außerhalb einer Funktion angelegt wurden, kannst du innerhalb der Funktion problemlos lesen:
wert = 1 def gibAus(): print(wert) gibAus()
Umgekehrt geht das nicht. Eine Variable, die innerhalb einer Funktion entsteht, ist lokal: Es gibt sie nur dort, und sie verschwindet, sobald die Funktion endet. Gleiches gilt für Parameter. Setzt du hinter den Aufruf von addiereZweiZahlen die Zeile print(summe), meldet Python:
Traceback (most recent call last): File "<stdin>", line 6, in <module> NameError: name 'summe' isn't defined
Das hat einen Vorteil: Zwei Funktionen dürfen beide eine Variable summe haben, ohne sich in die Quere zu kommen. Um ein Ergebnis nach draußen zu bringen, nimmst du return.
Soll die Funktion den Wert einer solchen Variablen aber ändern, brauchst du das Schlüsselwort global. Ohne es würde Python innerhalb der Funktion eine neue, eigene Variable gleichen Namens anlegen, und draußen bliebe alles unverändert.
wert = 1 def erhoehe(): global wert wert = wert + 1 print(wert) erhoehe()
Lässt du hier global wert weg, soll wert = wert + 1 eine lokale Variable aus sich selbst berechnen, die noch keinen Wert hat. Dann bricht das Programm mit dieser Meldung ab:
Traceback (most recent call last): File "<stdin>", line 7, in <module> File "<stdin>", line 4, in erhoehe NameError: local variable referenced before assignment
Die Meldung zeigt beide Stationen: den Aufruf in Zeile 7 und den Fehler in Zeile 4 innerhalb von erhoehe.
Sollen mehrere Variablen geändert werden, gibst du sie in einer Zeile durch Kommas getrennt an:
wert1 = 5 wert2 = 3 def tausche(): global wert1, wert2 temp = wert1 wert1 = wert2 wert2 = temp tausche() print(wert1) # gibt 3 aus print(wert2) # gibt 5 aus
Die Variable temp ist ein Zwischenlager. Ohne sie wäre der alte Wert von wert1 schon überschrieben, wenn wert2 ihn bekommen soll.
Bei Listen brauchst du
globalmeist nicht: Einliste.append(5)oderliste[0] = 7ändert den Inhalt der vorhandenen Liste und funktioniert auch ohne. Nötig wirdglobalerst, wenn du der Variablen eine komplett neue Liste zuweist, etwa mitliste = [].
Eine Funktion darf sich selbst aufrufen. Ohne eine Bedingung, die das beendet, geht das aber nicht lange gut: Auf dem PicoBoy ist schon nach ungefähr 25 bis 30 Selbstaufrufen Schluss, und das Programm bricht mit
RuntimeError: maximum recursion depth exceededab. Steht diese Meldung in der Konsole, ruft sich eine Funktion vermutlich aus Versehen selbst auf.
Übung
Schreibe eine Funktion zeichneHaus(x, y), die das „Haus vom Nikolaus“ an der übergebenen Position auf das Display zeichnet. Rufe sie dann zweimal mit verschiedenen Positionen auf. Tipp: Nimm dein Haus aus Schritt 1 und schreibe jede Koordinate als Abstand von der Position (x,y). Aus der Zahl 44 wird dann zum Beispiel x, aus 83 wird x + 39. Achte bei zwei Häusern darauf, dass beide auf das Display passen: Ein Haus aus Schritt 1 ist 40 Pixel breit und mit dem Dach etwa 60 Pixel hoch.