Ich habe versucht zu erklären, wozu der Python-Generator so einfach wie möglich ist.

Einführung

Es gibt andere Seiten, die Python-Generatoren erklären, aber es gab viele, die auf Englisch waren oder die sich für mich nicht richtig anfühlten. Deshalb erklärte ich die Generatoren auf meine eigene Weise, auch um meine Gedanken zu organisieren. Ich werde versuchen. Wenn ich mich weigere, bin ich im Grunde verwirrt, also könnte ich etwas Falsches sagen. Wenn Sie Fehler haben, kommentieren Sie diese bitte und es wird eine große Hilfe für Sie sein, um zu lernen. Die hier vorgestellte Verwendung des Generators ist nur ein paar Anwendungsbeispiele und bedeutet nicht, dass es keine andere Verwendung gibt.

Was ist ein Generator?

Es gibt andere großartige Artikel für detaillierte und genaue Erklärungen. Bitte beziehen Sie sich auf diese: Python Iterator und Generator

Um es kurz auszudrücken, stellen Sie es sich als "normale Funktion vor, bei der die return-Anweisung durch profit ersetzt wird". (Es ist anders, aber bitte verpassen Sie es vorerst). Wenn Sie Yield anstelle von Return schreiben, gibt ** nur ein Aufruf keinen Wert ** zurück. Stattdessen wird es mit einer for-Anweisung usw. aufgerufen und ** gibt Werte nacheinander zurück **. Es ist wahrscheinlich einfacher zu verstehen, wenn man ein Beispiel gibt.

example.py


def count_up():
    x = 0
    while True:
        yield x
        x += 1

Sicherlich ist es Ertrag, nicht Rückkehr. Und nach * Ausbeute * passiert etwas. Da nach der return-Anweisung keine Verarbeitung erfolgt, können Sie sofort erkennen, dass es sich um etwas anderes handelt, als nur die Rückgabe einer normalen Funktion zu ersetzen. Ich werde es viel erklären. Derzeit ruft dieser Generator zum Beispiel auf:

>>> countup()
<generator object countup at 0x101fa0468>
>>> for i in countup():
...     print(i)
...     if i == 5:
...             break
0
1
2
3
4
5

Sicherlich scheint es, dass kein Wert nur durch Aufrufen zurückgegeben wird. Beim Aufruf einer for-Anweisung werden die Werte stattdessen nacheinander zurückgegeben. Zu diesem Zeitpunkt gibt count_up bei jedem Aufruf den Wert von x zurück, erhöht jedoch bei jedem Aufruf den Wert von x. Dies ist, was der Prozess nach der Ausbeute kommt. Jetzt, da Sie wissen, was der Generator ist (keine Sorge, ich gebe Ihnen einige Beispiele, wenn Sie sich nicht sicher sind). Aber woran Sie hier wahrscheinlich denken, ist ** Wo benutzt du das? ** ** ** Ich denke, das bedeutet es. Dieses Mal werde ich den Zweck des Generators auf meine eigene Weise erklären.

Unterschied zwischen Generator und Funktion

Wie Sie aus dem vorherigen Beispiel sehen können, sind Generator und Funktion ** völlig unterschiedlich **. Generatoren sind ** Klassen ** überwiegend näher als Funktionen. Zum Beispiel im vorherigen Beispiel

>>> countup()

Kann klar verstanden werden, wenn interpretiert wird, dass eine Instanz der Klasse erstellt wurde. Der folgende Code funktioniert also auch:

>>> y = countup()
>>> for i in y:
...     print(i)
...     if i == 5:
...             break
0
1
2
3
4
5

Wenn Sie danach den folgenden Prozess ausführen,

>>> for i in y:
...     print(i)
...     if i == 10:
...             break
6
7
8
9
10

0 bis 5 sind verschwunden! Der Grund ist, dass sich der Generator bei jedem Aufruf ** daran erinnert, was getan wurde **. Mit anderen Worten, es hat einen ** Zustand **. Dies ist der größte Unterschied zur Funktion. Im obigen Beispiel ist x = 6 in y, wenn die erste for-Anweisung endet, und dies wird bis zur nächsten for-Anweisung fortgesetzt.

Warum ist das so wichtig? Betrachten wir zum Beispiel die Szene der Berechnung der Fibonacci-Zahlenfolge, die jeder liebt. Eine häufig eingeführte Berechnungsmethode unter Verwendung von Wiederholung ist wie folgt:

fibonacci_recursive.py


def fibonacci(n):
    if n == 0:
        return 0
    if n == 1:
        return 1
    return fibonacci(n-1) + fibonacci(n-2)

Es wäre schön, wenn n klein wäre, aber wenn n groß wäre, würde sich der Stapel füllen und ein Fehler würde ausgelöst. Auf der anderen Seite bei Verwendung eines Generators

fibonacci_generator.py


def fibonacci():
    a, b = 0, 1
    while 1:
        yield b
        a, b = b, a+b

Auf diese Weise wird es möglich, die Fibonacci-Sequenz zu berechnen, ohne den Stapel zu verschwenden, indem die Werte der letzten beiden Zeichenfolgen als Zustände gehalten werden.

Unterschied zwischen Generator und Liste

Wenn man sich nur die bisherigen Beispiele ansieht, denkt der Leser wahrscheinlich ** Ist List nicht gut? ** ** ** Ich denke, das bedeutet es. Wenn Sie nur von Grund auf neu drucken möchten, können Sie natürlich eine separate Liste verwenden. Wenn es für eine Liste nicht gut ist, ist es **, wenn es schwierig ist, die gesamte Liste im Speicher zu halten, und es unnötig ist **. Betrachten Sie beispielsweise dasselbe Beispiel für die Berechnung des N-ten Elements der Fibonacci-Sequenz mithilfe einer Liste:

fibonacci_list.py


f = [0, 1]
n = 2
while n < N:
    f.append(f[n-1] + f[n-2])
    n += 1

Wenn Sie nur den N-ten Wert erhalten möchten, sind die Werte in der Fibonacci-Sequenz vor dem N-3 eine Speicherverschwendung. Mit anderen Worten, die Szene, in der der Generator arbeitet, ist ** die Szene, in der Sie Werte nacheinander zurückgeben und einen Status haben müssen, aber nicht die gesamte Liste behalten müssen **. Ich möchte, dass Sie sich einen Automaten mit endlichen Zuständen und einem Ausgabesymbol vorstellen. Im Gegenteil, es ist nicht für Situationen geeignet, in denen Sie keinen separaten Status benötigen oder eine Liste führen müssen. Das erste Beispiel dient zum Berechnen einer Hash-Funktion für eine eingegebene Zahl, und das zweite Beispiel dient zum Erstellen einer Liste von Primzahlen. Im Folgenden sehen wir uns einige weitere praktische Beispiele an.

Praktische Verwendung des Generators

Phrasenanalyse

Eine Szene, in der der Generator tatsächlich verwendet wird, ist die Standardbibliothek für die Python-Phrasenanalyse: http://docs.python.jp/2/library/tokenize.html Die Phrasenanalyse ist ein Prozess, der häufig beim Kompilieren eines Programms ausgeführt wird. Sie betrachtet das Programm zeichenweise und unterteilt die Zeichenkette des Programms in wichtige Teile (sogenannte Token). Zum Beispiel def f(hoge, foo): Ich meine, def, f, (, hoge, foo, ), : Es wird wahrscheinlich in eine Token-Zeichenfolge mit dem Namen aufgeteilt. Sie können an der Zeichenfolge def erkennen, dass es sich um eine Funktionsdefinition handelt, f der Funktionsname ist und die durch Kommas getrennten Variablen zwischen "(" und ")", nachdem es sich um die Argumente handelt. Durch das Parsen von Phrasen werden diese Informationen auch zum Token hinzugefügt und die Token-Zeichenfolge an den nächsten Prozess übergeben (was möglicherweise etwas ungenau ist, weitere Informationen finden Sie in der Compiler-Dokumentation).

Was hier wichtig ist, ist, dass sich die Verarbeitung, wenn Sie das Zeichen ")" sehen, ändert, je nachdem, ob Sie "(" oder nicht) sehen, wenn Sie beispielsweise jedes Zeichen betrachten und analysieren. .. Das heißt, es muss einen ** Zustand ** haben. Sobald diese Funktion definiert ist, ** spielen die Informationen zu dieser Funktion keine Rolle **. Es wäre eine Verschwendung von Speicher, die Informationen des gesamten Programms einzeln zu speichern. Daher ist die Phrasenanalyse eine gute Szene für Generatoren, um eine aktive Rolle zu spielen.

Pipeline

Details werden auf der folgenden Seite erklärt. https://brett.is/writing/about/generator-pipelines-in-python/

Einfach ausgedrückt ist eine Generator-Pipeline ein Prozess, der mehrere Generatoren ** verbindet **. Ich hoffe, Sie können sich die Verarbeitung des Förderbandtyps von der Seite im Werk vorstellen. Das dargestellte Beispiel ist eine Pipeline, die die geraden Elemente einer bestimmten Liste von Ganzzahlen verdreifacht, sie in eine Zeichenfolge konvertiert und sie zurückgibt.

pipeline.py


def even_filter(nums):
    for num in nums:
        if num % 2 == 0:
            yield num
def multiply_by_three(nums):
    for num in nums:
        yield num * 3
def convert_to_string(nums):
    for num in nums:
        yield 'The Number: %s' % num

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pipeline = convert_to_string(multiply_by_three(even_filter(nums)))
for num in pipeline:
    print num

In diesem Beispiel haben die einzelnen Generatoren keinen Status, verwenden die Generatoren jedoch weiterhin effektiv. Es ist nicht notwendig, die gesamte Liste zu speichern, aber es kann gesagt werden, dass es notwendig ist, sie nacheinander zu verarbeiten. Sie mögen denken, dass die Funktionsverarbeitung in Ordnung ist, aber die Verarbeitung von ungeraden Werten ist im obigen Beispiel nur eine verschwenderische Berechnung. Aus diesem Grund ist ein Generator praktisch, der die Verarbeitung auf jedes Element einzeln anwenden kann.

Rekursiv

Die folgenden Websites enthalten detaillierte Erklärungen und Beispiele: http://www.unixuser.org/~euske/doc/python/recursion-j.html

Wie ich zuvor erklärt habe, besteht der große Vorteil von Generatoren darin, dass sie nacheinander verarbeitet werden können, ohne die gesamte Liste zu halten. Mit anderen Worten, es ist kompatibel mit Problemen, die durch iterative Verarbeitung unterteilt und gelöst werden können. Sie können sehen, dass dies sehr nahe an der Idee liegt, Probleme mit Wiederholungen zu lösen. Das Fibonacci-Sequenzbeispiel war ein Beispiel für das Ersetzen der Wiederholung durch einen Generator, aber Sie können den Generator natürlich auch rekursiv verwenden. Der Vorteil der Verwendung eines Generators anstelle einer Funktion besteht darin, dass Sie einen einmal generierten Wert sofort verwerfen können. Der Code, der den Generator rekursiv zum Durchlaufen der Baumstruktur verwendet, sieht beispielsweise folgendermaßen aus:

tree.py


class Node:
    def __init__(self, data):
        self.data = data
	self.left = None
	self.right = None
		

def traverse(node):
    if node is not None:
	    for x in traverse(node.left):
	        yield x
        yield t.dat
	    for x in traverse(node.right):
	        yield x

Übrigens, wenn Sie die neu aus der python3.3-Reihe hinzugefügte Anweisung "yield from" verwenden, ist die Funktion "traverse" noch sauberer.

def traverse(node):
    if node is not None:
	    yield from traverse(node.left):
        yield t.dat
	    yield from traverse(node.right)

Es wird sein.

Realisierung von Collout

Die folgenden Quellen enthalten detaillierte Anweisungen: http://masnun.com/2015/11/13/python-generators-coroutines-native-coroutines-and-async-await.html

Ein Collout ist eine Unterroutine, mit der Sie die Verarbeitung unterbrechen und die Verarbeitung in der Mitte fortsetzen können. In Corroutine können Sie den Wert nicht nur abrufen, sondern auch senden. Nehmen Sie zum Beispiel das folgende Beispiel:

coroutine.py


def coro():
    hello = yield "Hello"
    yield hello
 
 
c = coro()
print(next(c))
print(c.send("World"))

Hier sehen Sie, dass sich die Ausbeute auf der rechten Seite des Zuweisungsausdrucks befindet. Dann sendet die send-Methode die Zeichenfolge "World". Sie können sehen, dass die Eigenschaften von Generatoren mit Zuständen verwendet werden. Wenn Sie sich mit Corroutine befassen, wird dies ein weiterer Artikel sein, daher werde ich ihn hier nur vorstellen. Wenn Sie Lust dazu haben, können Sie auch einen Artikel über Corroutine veröffentlichen. Da natives Kolloutum aus Python 3.5 implementiert wurde, kann dieselbe Verarbeitung ohne Verwendung eines Generators realisiert werden.

Zusammenfassung

Der Generator ist ein schwer zu fassendes Konzept, aber ich denke, es ist überraschend einfach, ihn als ein Werkzeug zu betrachten, das einen Status hat und Werte in der Reihenfolge mit nur teilweiser Behandlung zurückgibt, ohne die gesamte Liste zu halten. Lasst uns alle den Generator benutzen und coole Programme schreiben! (Obwohl ich es noch nicht gemeistert habe).

Recommended Posts

Ich habe versucht zu erklären, wozu der Python-Generator so einfach wie möglich ist.
Ich habe versucht, die multiple Regressionsanalyse anhand konkreter Beispiele so einfach wie möglich zu erklären.
Ich habe versucht herauszufinden, ob ReDoS mit Python möglich ist
[Pyto] Ich habe versucht, ein Smartphone als Flick-Tastatur für den PC zu verwenden
Ich habe versucht, die Zusammenführungssortierung in Python mit möglichst wenigen Zeilen zu implementieren
Ich habe versucht, mit Selenium + Python einfach ein vollautomatisches Anwesenheitssystem zu erstellen
[Python] Ich habe versucht, den Typnamen als Zeichenfolge aus der Typfunktion abzurufen
Ich habe versucht, ein scheinbar Windows-Snipper-Tool mit Python zu implementieren
Ich möchte Timeout einfach in Python implementieren
Ich möchte einen Python-Generator viele Male iterieren
Ich habe versucht, einen Pseudo-Pachislot in Python zu implementieren
Für mich als Django-Anfänger (2) - Was ist MTV?
Ich habe versucht, einen eindimensionalen Zellautomaten in Python zu implementieren
[Markov-Kette] Ich habe versucht, die Zitate in Python einzulesen.
Ich habe versucht "Wie man eine Methode in Python dekoriert"
So einfach wie möglich eine GUI mit Python erstellen [tkinter edition]
Ich habe versucht, einen Bot für die Ankündigung eines Wiire-Ereignisses zu erstellen
Ich habe eine Stoppuhr mit tkinter mit Python gemacht
[1 Stunde Herausforderung] Ich habe versucht, eine Wahrsagerseite zu erstellen, die für Python zu geeignet ist
Ich habe "Streamlit" ausprobiert, das den Python-Code so wie er ist in eine Webanwendung verwandelt
Ich habe versucht, einen Generator zu erstellen, der mit Python eine C # -Containerklasse aus CSV generiert
Ich habe auch versucht, die Funktionsmonade und die Zustandsmonade mit dem Generator in Python nachzuahmen
[Python] Was ist eine Zip-Funktion?
[Python] Was ist eine with-Anweisung?
Ich habe versucht, Python zu berühren (Installation)
Ich habe versucht, Pytorchs Datensatz zu erklären
Python für Anweisung ~ Was ist iterierbar ~
Wofür ist der Python-Unterstrich (_)?
[5.] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
Ich habe eine Bibliothek erstellt, die Konfigurationsdateien mit Python einfach lesen kann
Ich habe versucht, eine Python-Datei in eine EXE-Datei zu verwandeln (Rekursionsfehler unterstützt)
[2nd] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
Ich habe versucht, mit Python einen regulären Ausdruck für "Betrag" zu erstellen
Wovon ich süchtig war, als ich ALE in Vim für Python einführte
[Python] Ich habe versucht, eine stabile Sortierung zu implementieren
Ich habe versucht, mit Python einen regulären Ausdruck von "Zeit" zu erstellen
[3.] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
[Python] Ein Memo, das ich versucht habe, mit Asyncio zu beginnen
Ich habe versucht, mit Python eine Liste von Primzahlen zu erstellen
Ich habe versucht, mit Python einen regulären Ausdruck von "Datum" zu erstellen
[Pandas] Ich habe versucht, Verkaufsdaten mit Python zu analysieren. [Für Anfänger]
Ich habe versucht, ein missverstandenes Gefangenendilemma in Python zu implementieren
Ich habe versucht, mit Selenium und Python einen regelmäßigen Ausführungsprozess durchzuführen
Ich habe versucht, mit Python eine 2-Kanal-Post-Benachrichtigungsanwendung zu erstellen
Ich habe versucht, eine ToDo-App mit einer Flasche mit Python zu erstellen
[4.] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
Ich habe versucht, Gesichtsmarkierungen mit Python und Dlib leicht zu erkennen
[1.] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
Ich habe versucht, Jojo mit LSTM ein seltsames Zitat zu machen
[Python] Ich habe versucht, Wörter, die für Anfänger schwer zu verstehen sind, auf leicht verständliche Weise zu erklären.
Mayungos Python-Lernfolge 4: Ich habe versucht zu sehen, was passiert, wenn Zahlen als Buchstaben behandelt werden
Ich habe versucht herauszufinden, ob m in dem sogenannten Bereichstyp oder Bereich wie n..m und Bereich (n, m) enthalten ist.
Ich habe versucht, einen Linebot zu erstellen (Implementierung)
Ich habe einen Docker-Container erstellt, um JUMAN ++, KNP, Python (für pyKNP) zu verwenden.
Ich habe versucht, die Behandlung von Python-Ausnahmen zusammenzufassen
Ich habe versucht, PLSA in Python zu implementieren