Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> Python

Python-Generatoren

Python-Generatoren

In diesem Tutorial erfahren Sie, wie Sie Iterationen einfach mit Python-Generatoren erstellen, wie sie sich von Iteratoren und normalen Funktionen unterscheiden und warum Sie sie verwenden sollten.

Video:Python-Generatoren

Generatoren in Python

Es gibt viel Arbeit beim Erstellen eines Iterators in Python. Wir müssen eine Klasse mit __iter__() implementieren und __next__() -Methode, interne Zustände verfolgen und StopIteration auslösen wenn es keine zurückzugebenden Werte gibt.

Dies ist sowohl langwierig als auch kontraintuitiv. Generator kommt in solchen Situationen zur Hilfe.

Python-Generatoren sind eine einfache Möglichkeit, Iteratoren zu erstellen. Alle oben erwähnten Arbeiten werden automatisch von Generatoren in Python erledigt.

Einfach gesagt ist ein Generator eine Funktion, die ein Objekt (Iterator) zurückgibt, über das wir iterieren können (jeweils ein Wert).


Generatoren in Python erstellen

Es ist ziemlich einfach, einen Generator in Python zu erstellen. Es ist so einfach wie das Definieren einer normalen Funktion, aber mit einem yield -Anweisung anstelle eines return Aussage.

Wenn eine Funktion mindestens einen yield enthält -Anweisung (kann andere yield enthalten oder return Anweisungen), wird es zu einer Generatorfunktion. Beide yield und return gibt einen Wert von einer Funktion zurück.

Der Unterschied besteht darin, dass während ein return Anweisung beendet eine Funktion vollständig, yield -Anweisung hält die Funktion an, speichert alle ihre Zustände und fährt später von dort aus bei aufeinanderfolgenden Aufrufen fort.


Unterschiede zwischen Generatorfunktion und Normalfunktion

So unterscheidet sich eine Generatorfunktion von einer normalen Funktion.

Hier ist ein Beispiel, um alle oben genannten Punkte zu veranschaulichen. Wir haben eine Generatorfunktion namens my_gen() mit mehreren yield Aussagen.

# A simple generator function
def my_gen():
    n = 1
    print('This is printed first')
    # Generator function contains yield statements
    yield n

    n += 1
    print('This is printed second')
    yield n

    n += 1
    print('This is printed at last')
    yield n

Eine interaktive Ausführung im Interpreter ist unten angegeben. Führen Sie diese in der Python-Shell aus, um die Ausgabe anzuzeigen.

>>> # It returns an object but does not start execution immediately.
>>> a = my_gen()

>>> # We can iterate through the items using next().
>>> next(a)
This is printed first
1
>>> # Once the function yields, the function is paused and the control is transferred to the caller.

>>> # Local variables and theirs states are remembered between successive calls.
>>> next(a)
This is printed second
2

>>> next(a)
This is printed at last
3

>>> # Finally, when the function terminates, StopIteration is raised automatically on further calls.
>>> next(a)
Traceback (most recent call last):
...
StopIteration
>>> next(a)
Traceback (most recent call last):
...
StopIteration

Eine interessante Sache, die im obigen Beispiel zu beachten ist, ist, dass der Wert der Variablen n wird zwischen jedem Aufruf gespeichert.

Im Gegensatz zu normalen Funktionen werden die lokalen Variablen nicht zerstört, wenn die Funktion nachgibt. Außerdem kann das Generator-Objekt nur einmal iteriert werden.

Um den Prozess neu zu starten, müssen wir ein weiteres Generatorobjekt mit etwas wie a = my_gen() erstellen .

Eine letzte Anmerkung ist, dass wir Generatoren direkt mit for-Schleifen verwenden können.

Dies liegt daran, dass ein for Schleife nimmt einen Iterator und iteriert darüber mit next() Funktion. Es endet automatisch bei StopIteration wird angehoben. Sehen Sie hier nach, wie eine for-Schleife tatsächlich in Python implementiert wird.

# A simple generator function
def my_gen():
    n = 1
    print('This is printed first')
    # Generator function contains yield statements
    yield n

    n += 1
    print('This is printed second')
    yield n

    n += 1
    print('This is printed at last')
    yield n


# Using for loop
for item in my_gen():
    print(item)

Wenn Sie das Programm ausführen, lautet die Ausgabe:

This is printed first
1
This is printed second
2
This is printed at last
3

Python-Generatoren mit einer Schleife

Das obige Beispiel ist weniger nützlich und wir haben es nur untersucht, um eine Vorstellung davon zu bekommen, was im Hintergrund passiert.

Üblicherweise werden Generatorfunktionen mit einer Schleife mit geeigneter Abbruchbedingung realisiert.

Nehmen wir ein Beispiel für einen Generator, der eine Zeichenfolge umkehrt.

def rev_str(my_str):
    length = len(my_str)
    for i in range(length - 1, -1, -1):
        yield my_str[i]


# For loop to reverse the string
for char in rev_str("hello"):
    print(char)

Ausgabe

o
l
l
e
h

In diesem Beispiel haben wir den range() verwendet Funktion, um den Index mithilfe der for-Schleife in umgekehrter Reihenfolge abzurufen.

Hinweis :Diese Generatorfunktion funktioniert nicht nur mit Strings, sondern auch mit anderen Arten von Iterablen wie Liste, Tupel usw.


Python-Generatorausdruck

Einfache Generatoren lassen sich mithilfe von Generatorausdrücken ganz einfach on-the-fly erstellen. Es macht das Bauen von Generatoren einfach.

Ähnlich wie die Lambda-Funktionen, die anonyme Funktionen erstellen, erstellen Generatorausdrücke anonyme Generatorfunktionen.

Die Syntax für den Generatorausdruck ähnelt der eines Listenverständnisses in Python. Aber die eckigen Klammern werden durch runde Klammern ersetzt.

Der Hauptunterschied zwischen einem Listenverständnis und einem Generatorausdruck besteht darin, dass ein Listenverständnis die gesamte Liste erzeugt, während der Generatorausdruck ein Element nach dem anderen erzeugt.

Sie haben eine faule Ausführung (Produzieren von Gegenständen nur, wenn danach gefragt wird). Aus diesem Grund ist ein Generatorausdruck viel speichereffizienter als ein entsprechendes Listenverständnis.

# Initialize the list
my_list = [1, 3, 6, 10]

# square each term using list comprehension
list_ = [x**2 for x in my_list]

# same thing can be done using a generator expression
# generator expressions are surrounded by parenthesis ()
generator = (x**2 for x in my_list)

print(list_)
print(generator)

Ausgabe

[1, 9, 36, 100]
<generator object <genexpr> at 0x7f5d4eb4bf50>

Wir können oben sehen, dass der Generatorausdruck nicht sofort das gewünschte Ergebnis lieferte. Stattdessen wurde ein Generatorobjekt zurückgegeben, das Artikel nur bei Bedarf produziert.

So können wir anfangen, Items vom Generator zu bekommen:

# Initialize the list
my_list = [1, 3, 6, 10]

a = (x**2 for x in my_list)
print(next(a))

print(next(a))

print(next(a))

print(next(a))

next(a)

Wenn wir das obige Programm ausführen, erhalten wir die folgende Ausgabe:

1
9
36
100
Traceback (most recent call last):
  File "<string>", line 15, in <module>
StopIteration

Generatorausdrücke können als Funktionsargumente verwendet werden. Bei einer solchen Verwendung können die runden Klammern weggelassen werden.

>>> sum(x**2 for x in my_list)
146

>>> max(x**2 for x in my_list)
100

Verwendung von Python-Generatoren

Es gibt mehrere Gründe, die Generatoren zu einer leistungsstarken Implementierung machen.

1. Einfach zu implementieren

Generatoren können im Vergleich zu ihrem Gegenstück in der Iteratorklasse klar und prägnant implementiert werden. Im Folgenden finden Sie ein Beispiel zur Implementierung einer Potenzfolge von 2 mithilfe einer Iteratorklasse.

class PowTwo:
    def __init__(self, max=0):
        self.n = 0
        self.max = max

    def __iter__(self):
        return self

    def __next__(self):
        if self.n > self.max:
            raise StopIteration

        result = 2 ** self.n
        self.n += 1
        return result

Das obige Programm war langwierig und verwirrend. Lassen Sie uns nun dasselbe mit einer Generatorfunktion tun.

def PowTwoGen(max=0):
    n = 0
    while n < max:
        yield 2 ** n
        n += 1

Da Generatoren Details automatisch verfolgen, war die Implementierung präzise und viel sauberer.

2. Speichereffizient

Eine normale Funktion zum Zurückgeben einer Sequenz erstellt die gesamte Sequenz im Speicher, bevor das Ergebnis zurückgegeben wird. Dies ist ein Overkill, wenn die Anzahl der Elemente in der Sequenz sehr groß ist.

Die Generatorimplementierung solcher Sequenzen ist speicherfreundlich und wird bevorzugt, da sie jeweils nur ein Element erzeugt.

3. Stellt den unendlichen Strom dar

Generatoren sind hervorragende Medien, um einen unendlichen Datenstrom darzustellen. Unendliche Ströme können nicht im Speicher gespeichert werden, und da Generatoren jeweils nur ein Element erzeugen, können sie einen unendlichen Datenstrom darstellen.

Die folgende Generatorfunktion kann (zumindest theoretisch) alle geraden Zahlen erzeugen.

def all_even():
    n = 0
    while True:
        yield n
        n += 2

4. Pipeline-Generatoren

Mehrere Generatoren können verwendet werden, um eine Reihe von Operationen zu leiten. Dies lässt sich am besten anhand eines Beispiels veranschaulichen.

Angenommen, wir haben einen Generator, der die Zahlen in der Fibonacci-Reihe erzeugt. Und wir haben einen weiteren Generator zum Quadrieren von Zahlen.

Wenn wir die Summe der Quadrate von Zahlen in der Fibonacci-Reihe herausfinden möchten, können wir dies auf folgende Weise tun, indem wir die Ausgabe von Generatorfunktionen zusammenfügen.

def fibonacci_numbers(nums):
    x, y = 0, 1
    for _ in range(nums):
        x, y = y, x+y
        yield x

def square(nums):
    for num in nums:
        yield num**2

print(sum(square(fibonacci_numbers(10))))

Ausgabe

4895

Dieses Pipelining ist effizient und einfach zu lesen (und ja, viel cooler!).


Python

  1. Python-Operatoren
  2. Python-Funktionsargumente
  3. Python-Wörterbuch
  4. Python-Generatoren
  5. Python-Schließungen
  6. Python-Dekorateure
  7. Python-Lambda-Funktionen mit BEISPIELE
  8. Python abs() Funktion:Beispiele für absolute Werte
  9. Python-Funktion round() mit BEISPIELE
  10. Python map() Funktion mit BEISPIELE