Wie sich eine Funktion selbst aufruft
Rekursion bedeutet, dass eine Funktion ein Problem löst, indem sie sich mit einem kleineren Problem selbst aufruft. Sie brauchen dafür nur zwei Dinge: einen Fall, der sich direkt lösen lässt, und einen Schritt, der das Problem kleiner macht.
Die Größe eines Ordners auf der Festplatte ist die Summe seiner Dateien plus die Größe jedes Unterordners. Für den Unterordner gilt derselbe Satz.
Am Ende dieser Lektion
Notiz
Ich kann eine rekursive Funktion mit Basisfall schreiben und ihre Aufrufe nachvollziehen.
Schlüsselwörter
| Begriff | Was er bedeutet | Beispiel |
|---|---|---|
| Rekursion | eine Funktion ruft sich selbst auf | |
| Basisfall | der Fall, den die Funktion ohne Selbstaufruf löst | n <= 1 |
| Rekursiver Fall | der Fall, der ein kleineres Problem selbst aufruft | |
| Aufrufstapel | die Liste der Aufrufe, die noch auf ein Ergebnis warten | |
| Rekursionstiefe | wie viele Aufrufe gleichzeitig offen sind |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ohne Basisfall hört die Rekursion nie auf
Die Fakultät von 4 ist 4 mal 3 mal 2 mal 1. Das ist 4 mal die Fakultät von 3. So erhalten Sie die Regel: n Fakultät ist n mal (n minus 1) Fakultät.
Der Basisfall ist die Fakultät von 1, und sie ist 1. Der rekursive Fall ruft die Funktion mit n minus 1 auf. Jeder Aufruf macht die Zahl kleiner, bis der Basisfall kommt.
Die Fakultät mit Ausgabe jedes Aufrufs
# Die Fakultaet: 4! = 4 * 3 * 2 * 1.
def fakultaet(n):
print("Aufruf mit n =", n)
if n <= 1:
return 1 # Basisfall: hier hoert die Rekursion auf
ergebnis = n * fakultaet(n - 1) # rekursiver Fall: ein kleineres Problem
print("Rueckgabe", ergebnis, "fuer n =", n)
return ergebnis
print(fakultaet(4))
# Aendern Sie 4 auf 6. Wie viele Aufrufe sehen Sie?
Der Aufrufstapel merkt sich die offenen Aufrufe
Ruft eine Funktion sich selbst auf, muss der erste Aufruf warten. Python merkt sich das auf dem Aufrufstapel: Oben liegt der neueste Aufruf, und nur der oberste arbeitet.
Hat der Basisfall ein Ergebnis, wird der Stapel von oben nach unten abgebaut. Jeder Aufruf rechnet mit dem Ergebnis des Aufrufs über ihm weiter.
Der Stapel bei fakultaet(3)
| Schritt | Was geschieht | Stapel (oben zuerst) |
|---|---|---|
| 1 | fakultaet(3) startet | fakultaet(3) |
| 2 | fakultaet(3) ruft fakultaet(2) auf | fakultaet(2), fakultaet(3) |
| 3 | fakultaet(2) ruft fakultaet(1) auf | fakultaet(1), fakultaet(2), fakultaet(3) |
| 4 | fakultaet(1) gibt 1 zurück | fakultaet(2), fakultaet(3) |
| 5 | fakultaet(2) gibt 2 mal 1 = 2 zurück | fakultaet(3) |
| 6 | fakultaet(3) gibt 3 mal 2 = 6 zurück | leer |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Im Lab: die Grenze der Rekursionstiefe
Der Stapel ist nicht unendlich groß. Python erlaubt nur eine feste Zahl offener Aufrufe und meldet danach einen Fehler. Der erste Befehl zeigt diese Grenze.
Der zweite und dritte rechnen mit der Fakultät aus der Standardbibliothek. Sie sehen, dass 6 Fakultät genau 6 mal 5 Fakultät ist.
Die Grenze der offenen Aufrufe
python3 -c "import sys; print(sys.getrecursionlimit())"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Zehn Fakultät
python3 -c "import math; print(math.factorial(10))"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Fünf Fakultät und der Faktor zur sechsten
python3 -c "import math; print(math.factorial(5), math.factorial(6) // math.factorial(5))"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Zwei Aufrufe pro Ebene wachsen sehr schnell
Eine Fibonacci-Zahl ist die Summe der beiden davor: 0, 1, 1, 2, 3, 5, 8. Die Funktion fib ruft sich deshalb zweimal auf, mit n minus 1 und mit n minus 2.
Der Basisfall sind die Zahlen unter 2. Ein Aufruf erzeugt zwei neue, jeder von ihnen wieder zwei. Die Zahl der Aufrufe wächst darum rasant.
Die Aufrufe von fib zählen
# Die Fibonacci-Zahlen: jede ist die Summe der beiden davor.
aufrufe = [0]
def fib(n):
aufrufe[0] = aufrufe[0] + 1
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
for n in [5, 10, 20]:
aufrufe[0] = 0
print("fib(", n, ") =", fib(n), "Aufrufe:", aufrufe[0])
# Probieren Sie 25. Warten Sie auf die Ausgabe und lesen Sie die Zahl der Aufrufe.
Wie viele Aufrufe macht fib(n)?
| n | fib(n) | Zahl der Aufrufe |
|---|---|---|
| 5 | 5 | 15 |
| 10 | 55 | 177 |
| 20 | 6765 | 21.891 |
| 30 | 832.040 | 2.692.537 |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ein häufiger Fehler
Warnung
Viele denken, der Basisfall sei nur eine Zusatzprüfung. Er ist der Grund, warum die Rekursion endet. Ohne ihn ruft sich die Funktion immer weiter auf, bis Python bei der Grenze der Tiefe mit einem Fehler abbricht. Der rekursive Aufruf muss außerdem zum Basisfall hinführen.
Weiterführend
Schreiben Sie potenz(basis, exponent) rekursiv. Der Basisfall ist der Exponent 0 mit dem Ergebnis 1. Sonst gilt: basis mal potenz(basis, exponent - 1).
Wie viele Aufrufe macht potenz(2, 10)? Vergleichen Sie mit python3 -c "print(2 ** 10)" im Lab.