Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.
Beide Seiten, vorherige Überarbeitung Vorherige Überarbeitung Nächste Überarbeitung | Vorherige Überarbeitung | ||
talit:generators [2024-05-17 13:22] – [Aufgabe 1: Fibonacci-Liste] hof | talit:generators [2024-05-22 18:20] (aktuell) – hof | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
# Iteratoren und Generatoren in Python | # Iteratoren und Generatoren in Python | ||
+ | < | ||
+ | |||
Eine [[wpde> | Eine [[wpde> | ||
Zeile 6: | Zeile 8: | ||
Wir möchten wiederverwendbaren Code schreiben, der die [[wpde> | Wir möchten wiederverwendbaren Code schreiben, der die [[wpde> | ||
+ | |||
### Aufgabe 1: Fibonacci-Liste | ### Aufgabe 1: Fibonacci-Liste | ||
- | Unser erster Versuch: Schreibe eine Funktion, die die ersten `n` Elemente der Fibonacci-Folge generiert und in einer Liste zurückgibt. Untenstehender Code funktioniert nur für $n<=10$ - ändere den Code so, dass er für beliebig grosse $n$ das richtige Resultat zurückgibt! | + | Unser erster Versuch: Schreibe eine Funktion, die die ersten `n` Elemente der Fibonacci-Folge generiert und in einer Liste zurückgibt. Untenstehender Code funktioniert nur für $n\le10$ -- ändere den Code so, dass er für beliebig grosse $n$ das richtige Resultat zurückgibt! |
- | < | + | |
- | "></iframe></ | + | < |
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | print(fibonacci(10))</bottom-editor></ | ||
<nodisp 0> | <nodisp 0> | ||
++++Lösung| | ++++Lösung| | ||
<code python> | <code python> | ||
- | def fibonacci(limit=10): | + | def fibonacci(n=10): |
result = [] | result = [] | ||
one = 0 | one = 0 | ||
two = 1 | two = 1 | ||
- | for i in range(limit): | + | for i in range(n): |
+ | # Python erlaubt Zuweisungen von Tupeln - | ||
+ | # natürlich lässt sich die Zuweisung auch auf | ||
+ | # mehrere Zeilen verteilen. | ||
one, two = two, one + two | one, two = two, one + two | ||
result.append(one) | result.append(one) | ||
Zeile 33: | Zeile 46: | ||
Natürlich könnten wir für beide Probleme eine eigene, effiziente Funktion schreiben, die ohne Liste auskommt - aber als faule Informatiker: | Natürlich könnten wir für beide Probleme eine eigene, effiziente Funktion schreiben, die ohne Liste auskommt - aber als faule Informatiker: | ||
- | Gesucht ist also ein Stück Code, das einen _Strom_ von Fibonacci-Zahlen liefert, die wir kontinuierlich konsumieren können, bis wir genug haben | + | Gesucht ist also ein Stück Code, das einen _Strom_ von Fibonacci-Zahlen liefert, die wir kontinuierlich konsumieren können, bis wir genug haben. |
- | . | + | |
## Iteratoren | ## Iteratoren | ||
Solche Strom-Objekte heissten _Iteratoren_. Ein Iterator hat nur eine einzige Funktion, `__next__`, die jeweils das nächste Element zurückgibt. Der Iterator muss sich irgendwie den Zustand merken, also wo in der Fibonacci-Folge er gerade steckt. Die Funktion wirft eine `StopIteration` Exception wenn es keine weiteren Elemente gibt. | Solche Strom-Objekte heissten _Iteratoren_. Ein Iterator hat nur eine einzige Funktion, `__next__`, die jeweils das nächste Element zurückgibt. Der Iterator muss sich irgendwie den Zustand merken, also wo in der Fibonacci-Folge er gerade steckt. Die Funktion wirft eine `StopIteration` Exception wenn es keine weiteren Elemente gibt. | ||
- | Die _built-in function_ [next](https:// | + | Die _built-in function_ [next](https:// |
- | . | + | |
### Aufgabe 2: Fibonacci-Iterator | ### Aufgabe 2: Fibonacci-Iterator | ||
Analysiere den untenstehenden Code und führe ihn aus. Ändere den Code, so dass die erste Fibonacci Zahl ausgegeben wird, die grösser als 1000 ist! | Analysiere den untenstehenden Code und führe ihn aus. Ändere den Code, so dass die erste Fibonacci Zahl ausgegeben wird, die grösser als 1000 ist! | ||
- | < | + | < |
- | "></ | + | |
+ | # Constructor - hier wird der Initial-Zustand gespeichert | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
- | < | + | iterator = FiboIterator() |
+ | print(next(iterator)) | ||
+ | print(next(iterator)) | ||
+ | print(next(iterator))</ | ||
+ | |||
+ | |||
+ | < | ||
++++Lösung| | ++++Lösung| | ||
<code python> | <code python> | ||
Zeile 61: | Zeile 92: | ||
++++ | ++++ | ||
</ | </ | ||
+ | |||
## Iterables | ## Iterables | ||
Zeile 80: | Zeile 112: | ||
Untenstehender Code fügt dem bestehenden Iterator ein Iterable hinzu, so dass wir eine for-Schleife nützen können: | Untenstehender Code fügt dem bestehenden Iterator ein Iterable hinzu, so dass wir eine for-Schleife nützen können: | ||
- | < | + | < |
- | "></iframe></ | + | |
+ | # Hier wird der Zustand gespeichert | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | class FiboIterable: | ||
+ | # Wird einmal aufgerufen, wenn Python die for-Schleife startet. | ||
+ | | ||
+ | | ||
+ | |||
+ | sequence = FiboIterable() | ||
+ | for num in sequence: | ||
+ | | ||
+ | | ||
+ | | ||
+ | </bottom-editor></ | ||
+ | |||
+ | Die Funktionen `__iter__` und `__next__` dürfen auch von derselben Klasse implementiert werden. | ||
- | Die Funktionen `__iter__` und `__next__` dürfen auch von derselben Klasse implementiert werden | ||
- | . | ||
## Yield | ## Yield | ||
Zeile 93: | Zeile 149: | ||
Ein Generator ist ein Iterable und kann damit auch als Ausdruck nach `in` in einer `for ... in < | Ein Generator ist ein Iterable und kann damit auch als Ausdruck nach `in` in einer `for ... in < | ||
- | < | + | < |
- | "></iframe></ | + | |
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | for num in fibo(): | ||
+ | | ||
+ | | ||
+ | | ||
+ | </bottom-editor></ | ||
### Iteration beenden | ### Iteration beenden | ||
Sind keine Elemente mehr übrig, wird einfach nichts zurückgegeben bzw. ein normales `return`. | Sind keine Elemente mehr übrig, wird einfach nichts zurückgegeben bzw. ein normales `return`. | ||
- | #### Aufgabe 3: Limitieren | + | ### Aufgabe 3: Limitieren |
Verändere den obigen Code um ein optionales Limit einzubauen, wieviele Elemente erzeugt werden sollen. | Verändere den obigen Code um ein optionales Limit einzubauen, wieviele Elemente erzeugt werden sollen. | ||
Zeile 105: | Zeile 171: | ||
Der folgende Code soll also `143` ausgeben: | Der folgende Code soll also `143` ausgeben: | ||
- | < | + | < |
- | "></iframe></ | + | |
+ | |||
+ | n=10 | ||
+ | print(f' | ||
+ | </bottom-editor></ | ||
## Yield From | ## Yield From | ||
Manchmal möchten wir eine andere Iteration (bzw. einen anderen Generator) in die gerade laufende Iteration einbinden. Dazu dienen die Keywords `yield from`. | Manchmal möchten wir eine andere Iteration (bzw. einen anderen Generator) in die gerade laufende Iteration einbinden. Dazu dienen die Keywords `yield from`. | ||
Zeile 112: | Zeile 183: | ||
Beispiel: ein einfacher Binärbaum besteht aus Knoten (_en_: Nodes), die jeweils bis zu zwei Kinder haben können. | Beispiel: ein einfacher Binärbaum besteht aus Knoten (_en_: Nodes), die jeweils bis zu zwei Kinder haben können. | ||
- | {{: | + | {{: |
Um den Baum zu traversieren (d.h. alle Knoten zu besuchen), können wir zum Beispiel die [[wpde> | Um den Baum zu traversieren (d.h. alle Knoten zu besuchen), können wir zum Beispiel die [[wpde> | ||
Zeile 118: | Zeile 189: | ||
Eine rekursive Umsetzung könnte wie folgt aussehen - beachte, wie `yield from` eingesetzt wird, um die rekursive Traversierung zu erreichen. | Eine rekursive Umsetzung könnte wie folgt aussehen - beachte, wie `yield from` eingesetzt wird, um die rekursive Traversierung zu erreichen. | ||
- | < | + | < |
- | "></iframe></ | + | |
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | tree = Node(5, Node(1), Node(7)) | ||
+ | |||
+ | for node in tree.in_order_traversal(): print (node.key) | ||
+ | </bottom-editor></ | ||
### Aufgabe 4: Pre-Order Traversierung | ### Aufgabe 4: Pre-Order Traversierung | ||
- | Füge eine Methode `pre_order_traveral` hinzu, die zuerst jeweils den Knoten selbst, dann den linken und rechten Teilbaum besucht. Die Reihenfolge des Besuchs sollte also `5 1 7` ausgeben. | + | Füge eine Methode `pre_order_traversal` hinzu, die zuerst jeweils den Knoten selbst, dann den linken und rechten Teilbaum besucht. Die Reihenfolge des Besuchs sollte also `5 1 7` ausgeben. |
### Weiter? | ### Weiter? | ||
Zurück zum [[talit: | Zurück zum [[talit: |