Iterator und Generator

PythonPythonBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Lab werden wir uns mit den eingebauten Iteratoren, Generatoren und Generatorausdrücken in Python befassen. Wir werden sehen, wie diese Konstrukte verwendet werden können, um effizient und eleganten Code in Python zu schreiben.

Ziele

  • Iterator
  • Generator
  • Generatorausdruck

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/ControlFlowGroup(["Control Flow"]) python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/ObjectOrientedProgrammingGroup(["Object-Oriented Programming"]) python(("Python")) -.-> python/ErrorandExceptionHandlingGroup(["Error and Exception Handling"]) python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python/ControlFlowGroup -.-> python/for_loops("For Loops") python/ControlFlowGroup -.-> python/list_comprehensions("List Comprehensions") python/FunctionsGroup -.-> python/function_definition("Function Definition") python/ObjectOrientedProgrammingGroup -.-> python/classes_objects("Classes and Objects") python/ErrorandExceptionHandlingGroup -.-> python/raising_exceptions("Raising Exceptions") python/AdvancedTopicsGroup -.-> python/iterators("Iterators") python/AdvancedTopicsGroup -.-> python/generators("Generators") subgraph Lab Skills python/for_loops -.-> lab-84{{"Iterator und Generator"}} python/list_comprehensions -.-> lab-84{{"Iterator und Generator"}} python/function_definition -.-> lab-84{{"Iterator und Generator"}} python/classes_objects -.-> lab-84{{"Iterator und Generator"}} python/raising_exceptions -.-> lab-84{{"Iterator und Generator"}} python/iterators -.-> lab-84{{"Iterator und Generator"}} python/generators -.-> lab-84{{"Iterator und Generator"}} end

Iterator

Ein Iterator ist ein Objekt, über das iteriert (in einer Schleife) werden kann. Ein Objekt, das Daten zurückgibt, jeweils ein Element nach dem anderen. In Python wird ein Iterator aus einem iterierbaren Objekt wie einer Liste, einem Tupel oder einem String erstellt.

Öffnen Sie einen neuen Python-Interpreter.

python3

Um in Python einen Iterator zu erstellen, müssen wir in unserem Objekt zwei Methoden implementieren: __iter__ und __next__.

__iter__ gibt das Iteratorobjekt selbst zurück. Die __next__-Methode gibt den nächsten Wert aus dem Iterator zurück. Wenn es keine weiteren Elemente gibt, die zurückgegeben werden können, sollte StopIteration ausgelöst werden.

Hier ist ein Beispiel für einen einfachen Iterator, der über eine Liste von Zahlen iteriert:

class MyIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        ## len() ist die Anzahl der Elemente in der Liste
        if self.index >= len(self.data):
            raise StopIteration
        result = self.data[self.index]
        self.index += 1
        return result

iterator = MyIterator([1, 2, 3, 4, 5])
for x in iterator:
    print(x)

Ausgabe:

1
2
3
4
5

Iteratoren sind nützlich, weil sie uns ermöglichen, die Elemente eines Iterierbaren nacheinander zuzugreifen, anstatt alle Elemente auf einmal in den Speicher zu laden. Dies kann besonders nützlich sein, wenn es um große Datensätze geht, die nicht in den Speicher passen.

Iteratoren werden auch verwendet, um die verzögerte Auswertung in Python zu implementieren. Dies bedeutet, dass die Elemente eines Iterators erst dann erzeugt werden, wenn sie benötigt werden, anstatt alle Elemente im Voraus zu erzeugen. Dies kann ein effizienterer Ansatz sein, da es uns ermöglicht, unnötige Elemente zu vermeiden, die erzeugt und gespeichert werden müssen.

Wenn Sie ein Element nach dem anderen aus einem Iterator erhalten möchten, können Sie die next()-Funktion verwenden. Diese Funktion gibt das nächste Element aus dem Iterator zurück. Wenn es keine weiteren Elemente gibt, wird eine StopIteration-Ausnahme ausgelöst.

iterator = MyIterator([1, 2, 3, 4, 5])
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))

## StopIteration
print(next(iterator))

Ausgabe:

1
2
3
4

## StopIteration

Hier sind einige häufige Anwendungsfälle für Iteratoren in Python:

  1. Iterieren über die Elemente eines großen Datensatzes, jeweils ein Element nach dem anderen.
  2. Implementieren der verzögerten Auswertung eines großen Datensatzes.
  3. Implementieren von benutzerdefiniertem Iterationslogik in einer Klasse.
  4. Iteratoren sind ein leistungsstarkes Werkzeug in Python und können verwendet werden, um effizienten und eleganten Code zu schreiben.

Generator

Ein Generator ist ein spezieller Typ von Iterator, der mit einer Funktion erstellt wird. Es ist eine einfache Möglichkeit, einen Iterator mit einer Funktion zu erstellen.

Eine Generatorfunktion wird wie eine normale Funktion definiert, aber anstelle des return-Schlüsselworts, um einen Wert zurückzugeben, verwendet sie das yield-Schlüsselwort. Wenn die Generatorfunktion aufgerufen wird, wird der Funktionskörper nicht sofort ausgeführt. Stattdessen gibt sie ein Generatorobjekt zurück, das verwendet werden kann, um den Funktionskörper nach Bedarf auszuführen.

Die Generatorfunktion kann überall in ihrem Körper eine yield-Anweisung haben. Wenn die Generatorfunktion aufgerufen wird, wird der Funktionskörper nicht sofort ausgeführt. Stattdessen gibt sie ein Generatorobjekt zurück, das verwendet werden kann, um den Funktionskörper nach Bedarf auszuführen.

Hier ist ein Beispiel für eine Generatorfunktion, die die Quadrate einer Liste von Zahlen generiert:

def my_generator(data):
    for x in data:
        yield x**2

for x in my_generator([1, 2, 3, 4, 5]):
    print(x)

Ausgabe:

1
4
9
16
25

Generatoren sind nützlich, weil sie uns ermöglichen, Elemente nach Bedarf zu generieren, anstatt alle Elemente im Voraus zu generieren. Dies kann ein effizienterer Ansatz sein, da es uns ermöglicht, unnötige Elemente zu vermeiden, die erzeugt und gespeichert werden müssen.

Generatoren werden auch verwendet, um die verzögerte Auswertung in Python zu implementieren. Dies bedeutet, dass die Elemente eines Generators erst dann erzeugt werden, wenn sie benötigt werden, anstatt alle Elemente im Voraus zu erzeugen. Dies kann ein effizienterer Ansatz sein, da es uns ermöglicht, unnötige Elemente zu vermeiden, die erzeugt und gespeichert werden müssen.

Hier sind einige häufige Anwendungsfälle für Generatoren in Python:

  1. Generieren von Elementen nach Bedarf, anstatt alle Elemente im Voraus zu generieren.
  2. Implementieren der verzögerten Auswertung eines großen Datensatzes.
  3. Implementieren von benutzerdefiniertem Iterationslogik in einer Funktion.
  4. Generatoren sind ein leistungsstarkes Werkzeug in Python und können verwendet werden, um effizienten und eleganten Code zu schreiben.

Unterschiede zwischen Iterator und Generator

Der Hauptunterschied zwischen einem Iterator und einem Generator liegt in der Art der Implementierung.

Ein Iterator ist ein Objekt, das zwei Methoden implementiert: __iter__ und __next__. Die __iter__-Methode gibt das Iteratorobjekt selbst zurück, und die __next__-Methode gibt den nächsten Wert aus dem Iterator zurück.

Ein Generator ist eine Funktion, die das yield-Schlüsselwort verwendet, um einen Wert zurückzugeben. Wenn die Generatorfunktion aufgerufen wird, wird der Funktionskörper nicht sofort ausgeführt. Stattdessen gibt sie ein Generatorobjekt zurück, das verwendet werden kann, um den Funktionskörper nach Bedarf auszuführen.

Hier ist eine Zusammenfassung der Hauptunterschiede zwischen Iteratoren und Generatoren:

  1. Iteratoren sind Objekte, die die __iter__- und __next__-Methoden implementieren. Sie werden aus iterierbaren Objekten wie Listen, Tupeln oder Strings erstellt.
  2. Generatoren sind Funktionen, die das yield-Schlüsselwort verwenden, um einen Wert zurückzugeben. Sie werden durch Aufrufen einer Generatorfunktion erstellt.
  3. Iteratoren können mit einer Klasse implementiert werden, während Generatoren mit einer Funktion implementiert werden.
  4. Iteratoren geben jeweils ein Element zurück, während Generatoren ein Generatorobjekt zurückgeben, das verwendet werden kann, um Elemente nach Bedarf zu generieren.
  5. Iteratoren werden verwendet, um die Elemente eines iterierbaren Objekts nacheinander zuzugreifen, während Generatoren verwendet werden, um Elemente nach Bedarf zu generieren.

Insgesamt sind sowohl Iteratoren als auch Generatoren nützliche Werkzeuge für das Iterieren über eine Sequenz von Elementen in Python. Sie ermöglichen es uns, die Elemente einer Sequenz nacheinander zuzugreifen oder zu generieren, was effizienter sein kann als das Generieren aller Elemente im Voraus.

Fortgeschrittenes Beispiel: Primzahlgenerator

In diesem Beispiel werden wir einen Generator erstellen, der Primzahlen generiert.

Zunächst definieren wir eine Hilfsfunktion _is_prime, die True zurückgibt, wenn eine Zahl eine Primzahl ist, und False sonst:

def _is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

Nun definieren wir unsere Generatorfunktion prime_numbers:

def prime_numbers(n):
    for i in range(2, n+1):
        if _is_prime(i):
            yield i

Testen wir unseren Generator:

for prime in prime_numbers(20):
    print(prime)

Ausgabe:

2
3
5
7
11
13
17
19

Generatorausdruck

Ein Generatorausdruck ähnelt einer Listenkomprehension, erstellt jedoch statt einer Liste ein Generatorobjekt.

Ein Generatorausdruck wird in Klammern () definiert und kann einen oder mehrere for-Klauseln beinhalten. Er wird nach Bedarf ausgewertet und gibt ein Generatorobjekt zurück, das verwendet werden kann, um die Elemente des Ausdrucks nach Bedarf zu generieren.

Hier ist ein Beispiel für einen Generatorausdruck, der die Quadrate einer Liste von Zahlen generiert:

generator = (x**2 for x in [1, 2, 3, 4, 5])
for x in generator:
    print(x)

Ausgabe:

1
4
9
16
25

Generatorausdrücke sind nützlich, weil sie uns ermöglichen, Elemente nach Bedarf zu generieren, anstatt alle Elemente im Voraus zu generieren. Dies kann ein effizienterer Ansatz sein, da es uns ermöglicht, unnötige Elemente zu vermeiden, die erzeugt und gespeichert werden müssen.

Generatorausdrücke werden auch verwendet, um die verzögerte Auswertung in Python zu implementieren. Dies bedeutet, dass die Elemente eines Generatorausdrucks erst dann erzeugt werden, wenn sie benötigt werden, anstatt alle Elemente im Voraus zu erzeugen. Dies kann ein effizienterer Ansatz sein, da es uns ermöglicht, unnötige Elemente zu vermeiden, die erzeugt und gespeichert werden müssen.

Hier sind einige häufige Anwendungsfälle für Generatorausdrücke in Python:

  1. Generieren von Elementen nach Bedarf, anstatt alle Elemente im Voraus zu generieren.
  2. Implementieren der verzögerten Auswertung eines großen Datensatzes.
  3. Schreiben von präzise und effizientem Code.

Generatorausdrücke sind ein leistungsstarkes Werkzeug in Python und können verwendet werden, um effizienten und eleganten Code zu schreiben.

Generatorausdruck und Listenkomprehension

Hier ist ein Beispiel für eine Listenkomprehension und einen Generatorausdruck, die die Quadrate einer Liste von Zahlen generieren:

## Listenkomprehension
squares = [x**2 for x in [1, 2, 3, 4, 5]]
print(squares)

## Generatorausdruck
squares_generator = (x**2 for x in [1, 2, 3, 4, 5])
for x in squares_generator:
    print(x)

Ausgabe:

[1, 4, 9, 16, 25]
1
4
9
16
25

Es gibt mehrere Gemeinsamkeiten und Unterschiede zwischen Listenkomprehension und Generatorausdruck:

Gemeinsamkeiten

  1. Sowohl Listenkomprehension als auch Generatorausdruck werden verwendet, um eine Sequenz von Elementen zu generieren.
  2. Beide verwenden die gleiche Syntax, mit einem oder mehreren for-Klauseln und einem Ausdruck, um die Elemente zu generieren.

Unterschiede

  1. Eine Listenkomprehension generiert eine Liste, während ein Generatorausdruck ein Generatorobjekt generiert.
  2. Eine Listenkomprehension generiert alle Elemente der Liste im Voraus, während ein Generatorausdruck die Elemente nach Bedarf generiert.
  3. Eine Listenkomprehension verwendet mehr Speicher, da sie alle Elemente in einer Liste speichert, während ein Generatorausdruck weniger Speicher verwendet, da er die Elemente nach Bedarf generiert.
  4. Eine Listenkomprehension wird normalerweise schneller ausgeführt, da sie alle Elemente im Voraus generiert, während ein Generatorausdruck normalerweise langsamer ist, da er die Elemente nach Bedarf generiert.

Insgesamt sind sowohl Listenkomprehension als auch Generatorausdruck nützliche Werkzeuge für das Generieren einer Sequenz von Elementen in Python. Listenkomprehension ist im Allgemeinen schneller und verwendet mehr Speicher, während Generatorausdruck im Allgemeinen langsamer und weniger Speicher verwendet. Welcher von beiden verwendet werden soll, hängt von den spezifischen Anforderungen der Anwendung ab.

Zusammenfassung

In diesem Lab haben wir uns mit den eingebauten Iterators, Generators und Generatorausdrücken in Python beschäftigt. Wir haben gesehen, wie diese Konstrukte verwendet werden können, um effizienten und eleganten Code in Python zu schreiben. Wir haben auch ein Beispiel gesehen, wie Generatoren verwendet werden, um einen Primzahlgenerator zu implementieren.