Hier ist ein geistiges Bild von dem, was yield
tut.
Ich stelle mir einen Thread gerne als einen Stapel vor (auch wenn er nicht auf diese Weise implementiert ist).
Wenn eine normale Funktion aufgerufen wird, legt sie ihre lokalen Variablen auf den Stack, führt einige Berechnungen durch, leert dann den Stack und kehrt zurück. Die Werte der lokalen Variablen werden nie wieder gesehen.
Mit einem yield
Funktion, wenn ihr Code zu laufen beginnt (d. h. nachdem die Funktion aufgerufen wurde und ein Generatorobjekt zurückgibt, dessen next()
Methode aufgerufen wird), legt er seine lokalen Variablen ebenfalls auf den Stack und rechnet eine Weile. Aber dann, wenn er auf die yield
Anweisung, bevor sie ihren Teil des Stapels löscht und zurückkehrt, einen Schnappschuss ihrer lokalen Variablen macht und sie im Generatorobjekt speichert. Außerdem notiert er die Stelle in seinem Code, an der er sich gerade befindet (d.h. die bestimmte yield
Anweisung).
Es handelt sich also um eine Art eingefrorene Funktion, an der der Generator hängt.
Lorsque next()
aufgerufen wird, holt sie die Bestandteile der Funktion auf den Stapel und reanimiert sie. Die Funktion setzt ihre Berechnungen an der Stelle fort, an der sie aufgehört hat, ohne zu merken, dass sie gerade eine Ewigkeit im Kühlhaus verbracht hat.
Vergleichen Sie die folgenden Beispiele:
def normalFunction():
return
if False:
pass
def yielderFunction():
return
if False:
yield 12
Wenn wir die zweite Funktion aufrufen, verhält sie sich ganz anders als die erste. Die yield
Die Aussage mag unerreichbar sein, aber wenn sie irgendwo vorhanden ist, verändert sie die Art dessen, womit wir es zu tun haben.
>>> yielderFunction()
<generator object yielderFunction at 0x07742D28>
Aufruf von yielderFunction()
führt seinen Code nicht aus, sondern macht aus dem Code einen Generator. (Vielleicht ist es eine gute Idee, solche Dinge mit dem yielder
Präfix zur besseren Lesbarkeit).
>>> gen = yielderFunction()
>>> dir(gen)
['__class__',
...
'__iter__', #Returns gen itself, to make it work uniformly with containers
... #when given to a for loop. (Containers return an iterator instead.)
'close',
'gi_code',
'gi_frame',
'gi_running',
'next', #The method that runs the function's body.
'send',
'throw']
Le site gi_code
y gi_frame
sind die Felder, in denen der eingefrorene Zustand gespeichert wird. Durchsuchen Sie sie mit dir(..)
können wir bestätigen, dass unser obiges mentales Modell glaubwürdig ist.