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 12:55] – [Iteratoren] 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. | + | Unser erster Versuch: Schreibe eine Funktion, die die ersten `n` Elemente der Fibonacci-Folge generiert und in einer Liste zurückgibt. |
- | <nodisp | + | <html>< |
+ | first_few = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] | ||
+ | result = [] | ||
+ | for i in range(n): | ||
+ | result.append(first_few[i]) | ||
+ | return result | ||
+ | |||
+ | print(fibonacci(10))</ | ||
+ | |||
+ | <nodisp 0> | ||
++++Lösung| | ++++Lösung| | ||
- | <html><iframe frameborder=" | + | <code python> |
- | "></iframe></ | + | def fibonacci(n=10): |
+ | result | ||
+ | one = 0 | ||
+ | | ||
+ | | ||
+ | # Python erlaubt Zuweisungen von Tupeln - | ||
+ | # natürlich lässt sich die Zuweisung auch auf | ||
+ | # mehrere Zeilen verteilen. | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | print(fibonacci(10)) | ||
+ | </code> | ||
++++ | ++++ | ||
</ | </ | ||
Zeile 21: | 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 49: | Zeile 92: | ||
++++ | ++++ | ||
</ | </ | ||
+ | |||
## Iterables | ## Iterables | ||
Zeile 68: | 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 81: | 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 93: | 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 100: | 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 106: | 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: |