Heim > Artikel > Backend-Entwicklung > Tiefes Verständnis von Generatoren in Python
Generatorkonzept
Der Generator speichert die Ergebnisse nicht in einer Reihe, sondern speichert den Status des Generators und gibt bei jeder Iteration einen Wert zurück, bis er auf eine StopIteration Finish-Ausnahme stößt.
Generatorsyntax
Generatorausdruck: Dieselbe Listenanalysesyntax, aber [] in der Listenanalyse durch () ersetzen
Was Generatorausdrücke bewirken können, ist eine Listenanalyse. Grundsätzlich kann es verarbeitet werden, Wenn die zu verarbeitende Sequenz jedoch relativ groß ist, ist die Listenanalyse speicherintensiver.
>>> gen = (x**2 für x in range(5))
>>> gen
>>> für g in gen:
... print(g, end='-')
...
0-1-4-9-16-
>>> für x in [0,1,2,3,4,5]:
... print(x, end='-')
...
0-1-2-3-4-5-
Generatorfunktion: Wenn das Schlüsselwort yield in der Funktion vorkommt, dann ist die Funktion keine gewöhnliche Funktion mehr, sondern eine Generatorfunktion.
Aber die Generatorfunktion kann eine unbegrenzte Reihenfolge erzeugen, sodass die Liste überhaupt nicht verarbeitet werden kann.
Die Funktion von yield besteht darin, eine Funktion in einen Generator umzuwandeln. Eine Funktion mit yield ist keine gewöhnliche Funktion mehr und der Python-Interpreter behandelt sie als Generator.
Das Folgende ist eine Generatorfunktion, die unendlich ungerade Zahlen erzeugen kann.
def odd():
n=1
while True:
yield n
n+=2
odd_num = odd()
count = 0
for o in odd_num:
if count >=5: break
print(o)
count +=1
Ähnliche Dinge können natürlich auch manuell erreicht werden Iteratoren schreiben Der Effekt ist, dass der Generator intuitiver und leichter zu verstehen ist
class Iter:
def __init__(self):
self.start=-1
def __iter__(self) :
return self
def __next__(self):
self.start +=2
return self.start
I = Iter()
for count in range(5):
print( next(I))
Exkurs: Der Generator enthält die Methoden __iter() und next__(), sodass Sie for direkt zum Iterieren verwenden können, es gibt jedoch keinen selbstgeschriebenen Iter Dazu gehört StopIteration. Die Iteration kann nur über eine manuelle Schleife durchgeführt werden.
>>> aus Sammlungen importieren Iterable
>>> >>>> >>>> ; iter(odd_num) ist odd_num
True>>> help(odd_num)
Hilfe zum Generatorobjekt:
odd = Klassengenerator(objekt)
| Hier definiert:
|
|. __iter__(self, /)
|. Implementieren Sie iter(self).
|
|. Implementieren Sie next(self) .
...
Sehen Sie sich die obigen Ergebnisse an. Jetzt können Sie sicher eine Schleife gemäß der Iterator-Methode durchführen!
Wenn die for-Schleife ausgeführt wird, führt jede Schleife den Code innerhalb der Fab-Funktion aus. Wenn sie Yield b erreicht, gibt die Fab-Funktion einen Iterationswert zurück. In der nächsten Iteration beginnt der Code mit der nächsten Anweisung von yield b. Die Ausführung wird fortgesetzt und die lokalen Variablen der Funktion sehen genauso aus wie vor der letzten Unterbrechung, sodass die Funktion weiter ausgeführt wird, bis sie erneut auf yield trifft. Es sieht so aus, als ob eine Funktion während der normalen Ausführung mehrmals durch yield unterbrochen wird und jede Unterbrechung den aktuellen Iterationswert über yield zurückgibt.
Ausbeute und Rückgabe
... yield 1
...>>> g=g1()
>>> g) bleibt nach der Ausführung der Yield-Anweisung hängen, sodass die Programmausführung zu diesem Zeitpunkt noch nicht beendet ist.1
>>> next(g) #Das Programm versucht, die Ausführung ab der nächsten Anweisung der yield-Anweisung zu starten und stellt fest, dass sie das Ende erreicht hat, sodass eine StopIteration-Ausnahme ausgelöst wird.Traceback (letzter Aufruf zuletzt):
Datei „
StopIteration
>>>
Wenn während der Ausführung eine Rückgabe auftritt, wird StopIteration direkt ausgelöst, um die Iteration zu beenden.
>>> >>> g=g2()
>>> #Das Programm bleibt an der Position, nachdem die yield 'a'-Anweisung ausgeführt wurde.
'a'
>>> next(g) #Das Programm stellt fest, dass die nächste Anweisung return ist, daher wird eine StopIteration-Ausnahme ausgelöst, sodass die yield 'b'-Anweisung niemals ausgeführt wird.
Traceback (letzter Aufruf zuletzt):
Datei „
StopIteration
Wenn nach der Rückgabe ein Wert zurückgegeben wird , dann ist dieser Wert die Beschreibung der StopIteration-Ausnahme, nicht der Rückgabewert des Programms.
Es gibt keine Möglichkeit für einen Generator, Return zu verwenden, um einen Wert zurückzugeben.
>>> next(g)
'hello'>>> next(g)
Traceback (letzter Anruf zuletzt):Datei „
StopIteration: world
Vom Generator unterstützte Methoden
>>> ; help(odd_num)
Hilfe zum Generatorobjekt:
odd = Klassengenerator(objekt)
|. Hier definierte Methoden:
......
|. close() -> raise GeneratorExit.
|. send(...) |.
|. Nächsten ausgegebenen Wert zurückgeben oder StopIteration auslösen.
|. throw(...)
|. throw(typ[,val[,tb]]) ->
|. Nächsten ausgegebenen Wert zurückgeben oder StopIteration auslösen.
......
close()
Generatorfunktion manuell schließen, nachfolgende Aufrufe werden durchgeführt Gibt direkt die StopIteration-Ausnahme zurück.
>>>... Ausbeute 1
... Ausbeute 2
... Ausbeute 3
...
>>> g=g4()
>>> next(g)
>>> g.close()
>>> ; next(g) #Nach dem Schließen funktionieren die Anweisungen yield 2 und yield 3 nicht mehrTraceback (letzter Aufruf zuletzt):
Datei „StopIteration
send()
Das größte Merkmal der Generatorfunktion besteht darin, dass sie eine externe Variable akzeptieren und diese zurückgeben kann, nachdem das Ergebnis basierend auf dem Variableninhalt berechnet wurde.
Dies ist der am schwierigsten zu verstehende Teil der Generatorfunktion und auch der wichtigste Teil. Die Implementierung der Coroutine, über die ich später sprechen werde, hängt davon ab.
def gen():
value=0
while True:
receive=yield value
if keep=='e':
value = 'got: % s' % empfangen
g=gen()
print(g.send(None))print(g.send('aaa'))
print( g.send( 3))
Ausführungsprozess:
über g.send(None) oder next(g ) kann der gestartet werden Generatorfunktion und führen Sie sie bis zum Ende der ersten yield-Anweisung aus.
Zu diesem Zeitpunkt wurde die Yield-Anweisung ausgeführt, dem Empfang wurde jedoch kein Wert zugewiesen.
Der Ertragswert gibt den Anfangswert 0 aus.
Hinweis: Sie können beim Starten der Generatorfunktion nur (Keine) senden. Wenn Sie versuchen, andere Werte einzugeben, erhalten Sie eine Fehlermeldung.
Über g.send('aaa') wird aaa übergeben und dem Empfang zugewiesen. Anschließend wird der Wert berechnet und an den while-Kopf zurückgegeben Die Aussage wird beendet.
Zu diesem Zeitpunkt gibt der Ertragswert „got: aaa“ aus und bleibt dann hängen.
Wenn wir g.send(' e'), führt das Programm break aus und verlässt dann die Schleife. Schließlich wird die gesamte Funktion ausgeführt, sodass eine StopIteration-Ausnahme ausgelöst wird.
Das endgültige Ausführungsergebnis lautet wie folgt:
0
erhalten: aaa
Traceback (letzter Aufruf zuletzt):
Datei „h.py“ , Zeile 14, in
print(g.send('e'))
wird zum Senden von Entering verwendet Eine Ausnahme kann eine systemdefinierte Ausnahme oder eine benutzerdefinierte Ausnahme beenden.
def gen():
while True:
try:
yield 'normal value'
yield 'normal value 2'
print('here')
außer ValueError ; .throw(ValueError))
print(next(g))
print(g.throw(TypeError))
Das Ausgabeergebnis ist:
normal Wert
wir haben hier ValueError
Normalwert
Normalwert 2
Datei „h.py“, Zeile 15, in
StopIteration
Erklärung:
print(next(g)): Der Normalwert wird ausgegeben und bleibt bei der Ausbeute „normal“. Wert 2 'Vorher.
Da g.throw(ValueError) ausgeführt wird, werden alle nachfolgenden Try-Anweisungen übersprungen, was bedeutet, dass yield „Normalwert 2“ nicht ausgeführt wird. Geben Sie dann die Ausnahmeanweisung ein und geben Sie We aus Habe hier ValueError.
print(next(g)) führt die Yield-Anweisung „Normalwert 2“ aus und bleibt an der Position nach der Ausführung der Anweisung.
g.throw(TypeError): Springt aus der Try-Anweisung, sodass print('here') nicht ausgeführt wird. Führen Sie dann die Break-Anweisung aus, springen Sie aus der While-Schleife und Erreichen Sie dann das Ende des Programms und führen Sie die StopIteration-Ausnahme aus.
Das Folgende ist ein umfassendes Beispiel zum Erweitern einer mehrdimensionalen Liste oder zum Reduzieren einer mehrdimensionalen Liste)
def flatten(nested):
#Wenn es sich um eine Zeichenfolge handelt, lösen Sie manuell TypeError aus.
if isinstance(nested, str):raise TypeError
for sublist in nested: for element in flatten(sublist):
#yield element
Print ('Got:' , Element)
Except Typeerror:
#Print ('Here')
Yield Nested
L = ['AAADF' ,3],2,4,[5,[6, [8,[9]],'ddf'],7]]
für num in flatten(L):
print(num)
Wenn es etwas schwierig ist Wenn Sie verstehen, ist es klarer, den Kommentar der Druckanweisung zu öffnen und anzuzeigen.
Yield from
Die von Yield generierte Funktion ist ein Iterator, daher fügen wir sie normalerweise in eine Schleifenanweisung ein, um das Ergebnis auszugeben.
Manchmal müssen wir den durch diese Ausbeute generierten Iterator in eine andere Generatorfunktion einfügen, nämlich in die Generatorverschachtelung.
Zum Beispiel:
def inner():
for i in range(10):yield i
def äußere(): g_inner=inner( ) # Dies ist ein Generator
while True:
res = g_inner.send(None)
g_outer=outer()
while True:
try :
print(g_outer.send(None))
außer StopIteration:
break
Zu diesem Zeitpunkt können wir die yield from-Anweisung verwenden, um unsere Arbeitsbelastung zu reduzieren.
def äußere2():
yield from inner()
Natürlich liegt der Schwerpunkt der yield from-Anweisung darauf, uns dabei zu helfen, automatisch Ausnahmen zwischen dem inneren und dem äußeren zu behandeln Hier sind zwei gut geschriebene Artikel, daher werde ich nicht zu ausführlich sein.
http://stackoverflow.com/questions/9708902/in-practice-what-are-the-main -uses-for-the-new-yield-from-syntax-in-python-3
Zusammenfassung
Nach der Entenmodelltheorie ist der Generator eine Art Iterator, der das kann mit for iterate durchgeführt werden.
Wenn next(generator) zum ersten Mal ausgeführt wird, wird das Programm nach der Ausführung der Yield-Anweisung angehalten und alle Parameter und Status werden gespeichert.
Wenn next(generator) erneut ausgeführt wird, wird es aus dem angehaltenen Zustand ausgeführt.
Sie können Parameter über generator.send(arg) übergeben, das das Coroutine-Modell ist.
Sie können eine Ausnahme über generator.throw(Exception) übergeben. Die throw-Anweisung verbraucht einen Yield.
Der Generator kann manuell über generator.close() geschlossen werden.
Das Obige ist das detaillierte Verständnis von Generatoren in Python. Weitere verwandte Artikel finden Sie im PHP-Chinesisch Website (www.php.cn)!