English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Einführung in Python

Flusskontrolle in Python

Funktionen in Python

Datentypen in Python

Dateioperationen in Python

Python Objekte und Klassen

Python Datum und Zeit

Erweiterte Kenntnisse in Python

Python Referenzhandbuch

Generator in Python

In diesem Artikel werden Sie lernen, wie man Iterationen mit Python-Generatoren einfach erstellt, wie sie sich von Iteratoren und regulären Funktionen unterscheiden und warum man sie verwenden sollte.

Was sind Generatoren in Python?

mit PythonaufbauenIteratorenEs gibt viele Kosten; Wir müssen eine Klasse mit __iter__() und __next__()-Methoden implementieren, um den internen Zustand zu verfolgen, StopIteration auszulösen, wenn es keine zu zurückgebenden Werte gibt, und so weiter.

Das ist sowohl langatmig als auch gegen die Intuition. In diesem Fall kann ein Generator hilfreich sein.

Generatoren in Python sind eine einfache Methode, Iteratoren zu erstellen. Alle oben genannten Kosten werden automatisch durch die Generatoren in Python gehandhabt.

Kurz gesagt, ein Generator ist eine Funktion, die ein Objekt (Iterator) zurückgibt, das iteriert werden kann (einmalig ein Wert).

Wie erstellt man in Python Generatoren?

Die Erstellung von Generatoren in Python ist sehr einfach. Es ist so einfach wie die Verwendung von yield-Statements anstelle von return-Statements, um eine reguläre Funktion zu definieren.

Wenn eine Funktion mindestens ein yield-Statement enthält (es kann andere yield- oder return-Statements enthalten), dann wird sie zu einer Generatorfunktion. Beide, yield und return, geben von der Funktion einige Werte zurück.

Der Unterschied liegt darin, dass eine yield-Statement die Funktion pausiert und alle Zustände speichert, um sie bei späteren Aufrufen fortzusetzen, wenn die return-Statement eine Funktion vollständig beendet.

Unterschiede zwischen der Generatorfunktion und der regulären Funktion

Das ist der Unterschied zwischen der Generatorfunktion undRegelmäßige FunktionenUnterschiede.

  • Generatorfunktionen enthalten eine oder mehrere yield-Statements.

  • Bei der Aufruf wird ein Objekt (Iterator) zurückgegeben, aber es wird nicht sofort ausgeführt.

  • Methoden wie __iter__() und __next__() werden automatisch implementiert. Daher können wir next() verwenden, um durch die Elemente zu navigieren.

  • Sobald die Funktion ein Ergebnis erzeugt hat, pausiert sie und der Kontrollfluss wird an den Aufrufer übergeben.

  • Lokale Variablen und ihr Zustand werden zwischen aufeinanderfolgenden Aufrufen gespeichert.

  • Schließlich wird bei weiterer Aufruf automatisch StopIteration ausgelöst, wenn die Funktion beendet wird.

Dies ist ein Beispiel, um alle genannten Punkte zu veranschaulichen. Wir haben eine my_gen() genannte Generatorfunktion, die durch mehrere yield-Statements definiert wird.

# Eine einfache Generator-Funktion
def my_gen():
    n = 1
    print('Dies ist das erste Mal, dass gedruckt wird')
    # Der Generator-Funktion enthält ein yield-Anweisung
    yield n
    n += 1
    print('Dies ist das zweite Mal, dass gedruckt wird')
    yield n
    n += 1
    print('Dies ist das letzte Mal, dass gedruckt wird')
    yield n

Die Interaktion in der Interpreterumgebung ist wie folgt dargestellt. Führen Sie diese Befehle im Python Shell aus, um die Ausgabe anzuzeigen.

>>> # Es wird ein Objekt zurückgegeben, aber es beginnt nicht sofort mit der Ausführung.
>>> a = my_gen()
>>> # Wir können next() verwenden, um diese Elemente zu durchlaufen.
>>> next(a)
Dies ist das erste Mal, dass gedruckt wird
1
>>> # Sobald die Funktion ein Ergebnis erzeugt hat, pausiert sie und der Kontrollfluss wird an den Aufrufer übergeben.
>>> # Lokale Variablen und ihr Zustand werden zwischen den aufeinanderfolgenden Aufrufen gemerkt.
>>> next(a)
Dies ist das zweite Mal, dass gedruckt wird
2
>>> next(a)
Dies ist das letzte Mal, dass gedruckt wird
3
>>> # Schließlich wird StopIteration automatisch ausgelöst, wenn die Funktion beendet wird und weiter aufgerufen wird.
>>> next(a)
Traceback (letzter Aufruf am Ende):
...
StopIteration
>>> next(a)
Traceback (letzter Aufruf am Ende):
...
StopIteration

Ein interessantes Detail, das im obigen Beispiel zu beachten ist, ist, dass zwischen den Aufrufen Variablennwerten.

Unterschiedlich von normalen Funktionen werden lokale Variablen nicht zerstört, wenn die Funktion erzeugt wird. Außerdem kann ein Generator-Objekt nur einmal iteriert werden.

Um den Prozess neu zu starten, müssen wir etwas wie = my_gen() verwenden, um einen neuen Generator-Objekt zu erstellen.

Hinweis:Letztendlich ist zu beachten, dass wir den Generator direkt mitfor-Schleifezusammen verwenden.

Dies liegt daran, dass der for-Schleife einen Iterator akzeptiert und ihn mit Hilfe der Funktion next() iteriert. Wenn StopIteration ausgelöst wird, endet er automatisch.Verstehen Sie, wie man in Python tatsächlich for-Schleifen implementiert.

# Eine einfache Generator-Funktion
def my_gen():
    n = 1
    print('Dies ist das erste Mal, dass gedruckt wird')
    # Der Generator-Funktion enthält ein yield-Anweisung
    yield n
    n += 1
    print('Dies ist das zweite Mal, dass gedruckt wird')
    yield n
    n += 1
    print('Dies ist das letzte Mal, dass gedruckt wird')
    yield n
# Verwendung des for-Schleifens
for item in my_gen():
    print(item)

Wenn das Programm ausgeführt wird, lautet die Ausgabe:

Dies ist das erste Mal, dass gedruckt wird
1
Dies ist das zweite Mal, dass gedruckt wird
2
Dies ist das letzte Mal, dass gedruckt wird
3

Python-Generator mit Schleifen

Der obige Beispiel ist nicht sehr nützlich, wir untersuchen es nur, um zu verstehen, was im Hintergrund passiert.

Normalerweise werden Generator-Funktionen durch einen mit einer angemessenen Abbruchbedingung versehenen Schleifen implementiert.

Lassen Sie uns mit einem Generator-Beispiel für die Umkehrung eines Strings beginnen.

def rev_str(my_str):
    length = len(my_str)
    for i in range(length - 1,-1,-1)
        yield my_str[i]
# Der for-Schleife wird verwendet, um den String umzukehren
# 输出:
# o
# l
# l
# e
# h
for char in rev_str("hello"):
     print(char)

In diesem Beispiel verwenden wir die Funktion range() mit einem for-Schleifendurchlauf, um die Indizes in umgekehrter Reihenfolge zu erhalten.

事实证明,此生成器函数不仅适用于字符串,还适用于其他种类的可迭代对象,例如list,tuple等。

Python生成器表达式

使用生成器表达式可以轻松地动态创建简单的生成器。它使建造生成器变得容易。

与lambda函数创建匿名函数相同,生成器表达式创建匿名生成器函数。

生成器表达式的语法类似于Python中的列表理解语法。但是将方括号替换为圆括号。

列表理解与生成器表达式之间的主要区别在于,虽然列表理解生成整个列表,但生成器表达式一次生成一个项目。

他们有点懒,只在需要时才生成项目。由于这个原因,生成器表达式比等价的列表理解的内存效率要高得多。

# 初始化列表
my_list = [1, 3, 6, 10]
# 使用列表理解对每个项目进行平方
# 输出: [1, 9, 36, 100]
[x**2 for x in my_list]
# 同样的事情可以使用生成器表达式来完成
# 输出: <generator object <genexpr> at 0x0000000002EBDAF8>
(x**2 for x in my_list)

上面我们可以看到生成器表达式没有立即产生所需的结果。相反,它返回了一个生成器对象,该对象带有按需生产的物品。

# 初始化list
my_list = [1, 3, 6, 10]
a = (x**2 for x in my_list)
# 输出: 1
print(next(a))
# 输出: 9
print(next(a))
# 输出: 36
print(next(a))
# 输出: 100
print(next(a))
# 输出: StopIteration
next(a)

生成器表达式可以在函数内部使用。以这种方式使用时,可以删除圆括号。

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

为什么在Python中使用生成器?

有几个原因使生成器成为一个有吸引力的实现。

1.易于实施

与它们的迭代器类对应项相比,生成器可以以一种清晰而简洁的方式实现。下面是一个使用iterator类实现2的幂序列的示例。

class PowTwo:
    def __init__(self, max = 0):
        self.max = max
    def __iter__(self):
        self.n = 0
        return self
    def __next__(self):
        if self.n > self.max:
            raise StopIteration
        result = 2 ** self.n
        self.n += 1
        return result

Dieser Code ist sehr lang. Nutzen Sie nun die Generator-Funktion, um die gleiche Operation auszuführen.

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

Da Generatoren die Details automatisch verfolgen, sind sie klar und einfacher zu implementieren.

2.Speicherersparnis

Eine normale Funktion, die eine Sequenz zurückgibt, erstellt vor dem Rückgabe der Ergebnisse die gesamte Sequenz im Speicher. Wenn die Anzahl der Elemente in der Sequenz groß ist, kann dies die Effizienz beeinträchtigen.

Die Implementierung des Generators für diese Sequenz ist speicherfreundlich und daher die beste Wahl, da nur ein Element nach dem anderen erzeugt wird.

3.Darstellung unendlicher Ströme

Generatoren sind ein hervorragendes Medium zur Darstellung unendlicher Datenflüsse. Unendliche Ströme können nicht im Speicher gespeichert werden, und da Generatoren nur ein Element nach dem anderen erzeugen, können sie unendliche Datenflüsse darstellen.

Das folgende Beispiel kann alle geraden Zahlen erzeugen (mindestens theoretisch).

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

4.Pipeline-Generator

Generatoren können zur Pipeline-Ordnung einer Reihe von Operationen verwendet werden. Ein Beispiel kann dies erklären.

Angenommen, dass wir eine bekannte Fast-Food-Kette-Logdatei haben. In der Logdatei gibt es eine Spalte (der4Spalte), die die Anzahl der每小时 verkauften Pizzen verfolgt, möchten wir sie summieren, um5Gesamtzahl der im Jahr verkauften Pizzen

Angenommen, dass alle Inhalte Zeichenketten sind und keine verfügbaren Zahlen als "N" markiert sind / A”.Generator-Implementierung kann wie folgt sein.

mit open('sells.log') as file:
    pizza_col = (line[3] for line in file)
    per_hour = (int(x) for x in pizza_col if x != 'N/A')
    print("Gesamtzahl der verkauften Pizzen = ", sum(per_hour))

Diese Pipeline ist effizient und leicht lesbar (ja, sehr cool!).