Generatoren in Python
Dieser Artikel erklärt Generatoren in Python.
YouTube Video
Generatoren in Python
Überblick
Python-Generatoren sind eine Art Iterator und eine leistungsstarke Funktion, um wiederholte Verarbeitung effizient durchzuführen. Sie ermöglichen das Schreiben von speichereffizientem Code, wenn große Datenmengen verarbeitet werden.
Was ist ein Generator?
Ein Generator in Python ist eine spezielle Funktion, die jeweils einen Wert erzeugt, definiert durch das Schlüsselwort yield
. Sein Merkmal ist, dass er die Ausführung unter Beibehaltung seines Zustands pausiert und später fortsetzen kann.
Grundlagen von yield
yield
ist ein Schlüsselwort, das einen Wert zurückgibt und gleichzeitig die Funktionsausführung pausiert.
1def simple_generator():
2 yield 1
3 yield 2
4 yield 3
5
6gen = simple_generator()
7
8print(next(gen)) # 1
9print(next(gen)) # 2
10print(next(gen)) # 3
- Beim Aufrufen gibt diese Funktion ein Generatorobjekt zurück, das Werte nacheinander liefert.
- Wenn Sie
next()
aufrufen, obwohl kein nächster Wert mehr vorhanden ist, tritt einStopIteration
-Fehler auf.
next()
und StopIteration
1def simple_generator():
2 yield 1
3 yield 2
4 yield 3
5
6gen = simple_generator()
7
8try:
9 while True:
10 value = next(gen)
11 print(value)
12except StopIteration:
13 print("Finished")
- Indem Sie den
StopIteration
-Fehler explizit auf diese Weise behandeln, können Sie erkennen, wann ein Generator abgeschlossen ist.
send(value)
send(value)
aufzurufen setzt den Generator fort und übergibt value
an die Stelle des yield
-Ausdrucks. Der gesendete Wert kann auf der Generatorseite als Rückgabewert des yield
-Ausdrucks empfangen werden. Beim ersten Aufruf kann mit send(value)
nur None
gesendet werden, deshalb muss next()
oder send(None)
verwendet werden.
1def gen():
2 x = yield 1
3 print(f"x = {x}")
4 y = yield 2
5 print(f"y = {y}")
6
7g = gen()
8print(next(g)) # -> 1 (value from yield 1)
9print(g.send(10)) # -> x = 10, 2 (value from yield 2)
10print(g.send(20)) # -> y = 20, StopIteration occurs
- Mit
send(10)
wird dasyield
des Generators zu einem Ausdruck, der 10 zurückgibt, und 10 wirdx
zugewiesen.
throw()
throw
aufzurufen setzt den Generator fort und löst eine Ausnahme an der Stelle des pausierten yield
aus. Die Ausnahme kann innerhalb des Generators behandelt werden, um die Verarbeitung fortzusetzen. Wenn die Ausnahme nicht abgefangen wird, wird sie nach außen weitergegeben und der Generator endet.
1def gen():
2 try:
3 yield 1
4 except ValueError as e:
5 print(f"Caught: {e}")
6 yield "recovered"
7
8g = gen()
9print(next(g)) # -> 1
10print(g.throw(ValueError("boom"))) # -> Caught: boom, "recovered"
- In diesem Code wird
throw
aufgerufen, um eine Ausnahme in den Generator einzufügen. Auf der Generatorseite wird die Ausnahme behandelt undrecovered
wird zurückgegeben.
close()
close()
aufzurufen beendet den Generator. Innerhalb des Generators kann die Bereinigung mit finally
durchgeführt werden. next()
oder send()
nach dem Aufruf von close()
aufzurufen löst einen StopIteration
-Fehler aus.
1def gen():
2 try:
3 yield 1
4 finally:
5 print("Cleaning up...")
6
7g = gen()
8print(next(g)) # -> 1
9g.close() # -> Cleaning up...
- Dieser Code zeigt, dass der Aufruf von
close()
den Generator beendet und den Bereinigungsprozess infinally
auslöst.
yield from
yield from
ist eine Syntax, die verwendet wird, um an einen Subgenerator zu delegieren. Es ist eine einfache Möglichkeit, innerhalb eines Generators einen weiteren Generator aufzurufen und alle dessen Werte an den äußeren Gültigkeitsbereich weiterzugeben.
1def sub_gen():
2 yield 1
3 yield 2
4
5def main_gen():
6 yield from sub_gen()
7 yield 3
8
9print(list(main_gen())) # -> [1, 2, 3]
- Dieser Code delegiert alle Werte vom Subgenerator mithilfe von
yield from
an den äußeren Generator und gibt anschließend3
zurück.
Beziehung zu Iteratoren
Generatoren implementieren intern __iter__()
und __next__()
und sind somit eine Art von Iterator. Daher sind sie vollständig kompatibel mit iterierbaren Operationen wie for
-Schleifen.
Integration mit for
-Schleifen
In Python verwendet eine for
-Schleife intern next()
, um Werte automatisch abzurufen.
1def simple_generator():
2 yield 1
3 yield 2
4 yield 3
5
6for value in simple_generator():
7 print(value)
Mit dieser Methode erfolgt auch die Behandlung von StopIteration
automatisch.
Erstellen unendlicher Generatoren
1def count_up(start=0):
2 while True:
3 yield start
4 start += 1
5
6counter = count_up()
7print(next(counter)) # 0
8print(next(counter)) # 1
Es ist möglich, unendliche Schleifen zu erstellen, aber beim Einsatz ist Vorsicht geboten.
Generatorausdrücke
Generatorausdrücke, die in Klammern geschrieben werden, ermöglichen die Definition von Generatoren mit einer Syntax ähnlich zu List Comprehensions.
1# List comprehension (generates the entire list at once)
2squares_list = [x**2 for x in range(5)]
3print(squares_list)
4
5# Generator expression
6squares_gen = (x**2 for x in range(5))
7for square in squares_gen:
8 print(square)
Im Gegensatz zu List Comprehensions laden sie nicht alle Elemente auf einmal in den Speicher, wodurch sie speichereffizienter sind.
Fehlerbehandlung in Generatoren
Ausnahmen können innerhalb eines Generators auftreten. In solchen Fällen verwendet man try-except
wie im normalen Python-Code.
1def safe_divide_generator(numbers, divisor):
2 """Yields results of dividing numbers by a given divisor safely."""
3 for number in numbers:
4 try:
5 yield number / divisor # Attempt to divide and yield result.
6 except ZeroDivisionError:
7 yield float('inf') # Return infinity if division by zero occurs.
8
9# Example usage
10numbers = [10, 20, 30]
11gen = safe_divide_generator(numbers, 0) # Create generator with divisor as 0.
12for value in gen:
13 print(value) # Output: inf, inf, inf
In diesem Beispiel erfolgt eine korrekte Fehlerbehandlung im Falle einer Division durch Null.
Stack-Trace eines Generators
Tritt innerhalb des Generators eine Ausnahme auf, wird sie ausgelöst, sobald der Generator fortgesetzt wird.
1def error_generator():
2 """A generator that yields values and raises an error."""
3 yield 1
4 raise ValueError("An error occurred") # Raise a ValueError intentionally.
5 yield 2
6
7gen = error_generator()
8print(next(gen)) # Output: 1 (first value yielded)
9try:
10 print(next(gen)) # Attempt to get the next value, which raises an error
11except ValueError as e:
12 print(e) # Output: An error occurred (exception message is printed)
- Dieser Generator liefert zuerst
1
zurück. Der beim Fortsetzen ausgelöste Fehler wird abgefangen und als Fehlermeldung angezeigt.
Beispiele für die Verwendung von Generatoren
Zeilenweises Lesen einer Datei (geeignet für große Dateien)
1def read_large_file(filepath):
2 with open(filepath, 'r') as f:
3 for line in f:
4 yield line.strip()
- Diese Funktion liest eine Textdatei zeilenweise mit einem Iterator ein, entfernt Leerzeichen von jeder Zeile und gibt diese als Generator zurück, sodass große Dateien mit geringem Speicherverbrauch verarbeitet werden können.
Generator für die Fibonacci-Folge
1def fibonacci(limit):
2 a, b = 0, 1
3 while a < limit:
4 yield a
5 a, b = b, a + b
6
7for n in fibonacci(100):
8 print(n)
- Dieser Code verwendet einen Generator, um der Reihe nach Fibonacci-Zahlen zu erzeugen, die unter dem angegebenen Grenzwert liegen, und gibt sie mit einer
for
-Schleife aus.
Anwendungsfälle
Generatoren können auch in den folgenden Szenarien verwendet werden.
- Sequenzielle Verarbeitung von großen CSV- oder Logdateien
- API-Paginierung
- Verarbeitung von Streaming-Daten (z. B. Kafka, IoT-Geräte)
Zusammenfassung
Konzept | Kernaussage |
---|---|
yield |
Pausiert und gibt einen Wert zurück |
Generatorfunktion | Eine Funktion, die yield enthält und beim Aufruf einen Iterator zurückgibt |
Vorteile | Speichereffizient und ideal für die Verarbeitung großer Datenmengen |
Generatorausdruck | Ermöglicht eine knappe Syntax wie (x for x in iterable) |
Durch die Verwendung von Generatoren können große Datenmengen effizient verarbeitet werden, während Speicher gespart und der Code übersichtlich gehalten wird.
Sie können den obigen Artikel mit Visual Studio Code auf unserem YouTube-Kanal verfolgen. Bitte schauen Sie sich auch den YouTube-Kanal an.