Python für Schleifen- und Iteratorverhalten
Ich wollte verstehen, ein bisschen mehr über iterators
, also bitte korrigieren Sie mich, wenn ich falsch bin.
Ein iterator ist ein Objekt, das einen Zeiger auf das nächste Objekt und liest sich wie ein Puffer oder stream (z.B. eine verkettete Liste). Sie sind besonders effizient, denn alle sagen Sie, was ist weiter von Referenzen anstelle von Indexierung.
Aber ich verstehe immer noch nicht warum ist das folgende Verhalten passiert:
In [1]: iter = (i for i in range(5))
In [2]: for _ in iter:
....: print _
....:
0
1
2
3
4
In [3]: for _ in iter:
....: print _
....:
In [4]:
Nach einer ersten Schleife durch den iterator (In [2]
) es ist, als ob es war, verbraucht und leer, so dass die zweite Schleife (In [3]
) druckt nichts.
Allerdings habe ich nie einen neuen Wert zugewiesen, der iter
variable.
Was passiert wirklich unter der Haube des for
Schleife?
InformationsquelleAutor der Frage Matteo | 2015-04-02
Du musst angemeldet sein, um einen Kommentar abzugeben.
Dein Verdacht ist richtig: der iterator ist verbraucht worden.
In der Aktualität, Ihre iterator ist ein generator, das ist ein Objekt, das die Fähigkeit hat, zu Durchlaufen nur einmal.
Der Grund, warum Sie effizient sind, hat nichts mit dir zu sagen, was ist weiter "als Verweis." Sie sind effizient, weil Sie nur erzeugen, das nächste Element auf Anfrage; alle Elemente generiert werden und nicht auf einmal. In der Tat, können Sie eine unendliche generator:
Einige andere Korrekturen zu verbessern Ihr Verständnis:
for
in
Annahme eines wiederholenden Objekt, als zweites argument.list
oderdict
oder einestr
Objekt (string), oder ein Benutzer-definierter Typ, der die erforderliche Funktionalität bereitstellt.iter
- Funktion auf das Objekt angewendet wird, um ein iterator (übrigens: nicht verwendeniter
als Variablennamen in Python, wie Sie getan haben - es ist eines der Stichworte). Eigentlich, um genauer zu sein, die das Objekt__iter__
Methode aufgerufen wird (dies ist zum größten Teil, alleiter
Funktion ohnehin tut;__iter__
ist ein Python-die sogenannten "magic methods").__iter__
erfolgreich ist, wird die Funktionnext()
angewendet wird, um die wiederholenden Objekt immer und immer wieder in einer Schleife, und die erste variable geliefertfor
in
zugeordnet ist, das Ergebnis dernext()
Funktion. (Sie erinnern sich: die wiederholenden Objekt könnte ein generator oder ein container-Objekt iterator, oder jede andere wiederholenden Objekt.) Eigentlich, um genauer zu sein: es ruft der iterator-Objekt__neben__
Methode, eine weitere "Magische Methode" verwendet wird.for
Schleife endet, wennnext()
wirft dieStopIteration
Ausnahme (die in der Regel passiert, wenn die iterierbar nicht ein anderes Objekt, um nachzugeben, wennnext()
genannt wird).Können Sie "von Hand" implementieren einer
for
- Schleife in python-dieser Weg (wahrscheinlich nicht perfekt, aber nahe genug):Gibt es so ziemlich keinen Unterschied zwischen oben und deinen Beispiel-code.
Eigentlich der interessantere Teil eines
for
- Schleife nicht diefor
, aber diein
. Mitin
selbst erzeugt einen anderen Effekt alsfor
in
, aber es ist sehr nützlich, um zu verstehen, wasin
hat mit seinen Argumenten, dafor
in
implementiert sehr ähnlich Verhalten.Wenn allein verwendet, die
in
Schlagwort ruft zuerst das Objekt__enthält__
Methode, das ist noch eine weitere "Magische Methode" verwendet wird (beachten Sie, dass dieser Schritt übersprungen wird, wenn mitfor
in
). Mitin
von selbst auf einen container, die Sie tun können, Dinge wie diese:Wenn die wiederholenden Objekt ist NICHT in einem container (d.h. es muss nicht ein
__contains__
- Methode)in
weiter versucht, rufen Sie das Objekt__iter__
Methode. Wie vorher gesagt: die__iter__
- Methode gibt zurück, was man in Python als iterator. Im Prinzip ist ein iterator ist ein Objekt, das Sie verwenden können, die eingebaute generische Funktionnext()
auf1. Ein generator ist nur eine Art von iterator.__iter__
erfolgreich ist, diein
Schlüsselwort gilt die Funktionnext()
der wiederholenden Objekt, über und über wieder. (Sie erinnern sich: die wiederholenden Objekt könnte ein generator oder ein container-Objekt iterator, oder jede andere wiederholenden Objekt.) Eigentlich, um genauer zu sein: es ruft der iterator-Objekt__neben__
- Methode).__iter__
Methode gibt ein iteratorin
fällt dann zurück auf die alten Stil-iteration-Protokoll über das Objekt__getitem__
Methode2.TypeError
Ausnahme.Wenn Sie möchten, erstellen Sie Ihre eigenen Objekttyp zu Durchlaufen (ich.e, die Sie verwenden können
for
in
oder nurin
auf Sie), ist es nützlich zu wissen über dieyield
Schlüsselwort, das verwendet wird, in Generatoren (wie oben erwähnt).Anwesenheit von
yield
schaltet eine Funktion oder Methode in einem generator statt einer regulären Funktion/Methode. Sie brauchen nicht die__next__
Methode, wenn Sie mit einem generator (es bringt__next__
zusammen mit automatisch).Wenn Sie möchten, erstellen Sie Ihre eigenen container-Objekt Typ (ich.e, die Sie verwenden können
in
auf es sich von selbst, aber NICHTfor
in
), Sie brauchen nur die__contains__
Methode.1 Beachten Sie, dass, werden ein iterator ist ein Objekt implementieren muss,das iterator-Protokoll. Dies bedeutet nur, dass sowohl die
__next__
und__iter__
Methoden müssen richtig umgesetzt (Generatoren kommen mit dieser Funktionalität "for free", so dass Sie nicht brauchen, um über es, wenn mit Ihnen). Beachten Sie auch, dass die___next__
Methode ist tatsächlichnext
(ohne Unterstriche) in Python 2.2 Siehe diese Antwort für die verschiedenen Möglichkeiten zum erstellen von wiederholenden Klassen.
InformationsquelleAutor der Antwort Rick Teachey
For-Schleife im Grunde ruft die
next
Methode, ein Objekt, das angewendet wird (__next__
in Python 3).Können Sie dies simulieren, indem Sie einfach tun:
In diesem Punkt gibt es keine nächste element in der Eingabe-Objekt. So, dies zu tun:
Folge
StopIteration
Ausnahme geworfen. An dieser Stellefor
zu stoppen. Und iterator werden kann jedes Objekt die Antworten auf dienext()
Funktion und wirft die Ausnahme, wenn es keine weiteren Elemente mehr. Es muss nicht jedes Zeiger-oder Referenz - (es gibt keine solche Dinge in python sowieso in C/C++ - Sinne), verkettete Listen, etc.InformationsquelleAutor der Antwort Marcin
Es ist eine iterator-Protokoll von python, die definiert, wie die
for
- Anweisung verhält sich mit Listen und dicts, und andere Dinge, die durchgeschliffen werden können über.Ist es in der python-docs hier und hier.
Den Weg der iterator-Protokoll arbeitet in der Regel in form eines python-generator. Wir
yield
einen Wert, solange wir einen Wert haben, bis wir das Ende erreichen und dann heben wirStopIteration
Also schreiben wir unseren eigenen iterator:
Ist das Ergebnis:
Ein paar Dinge zu beachten. Die my_iter ist eine Funktion. my_iter() gibt einen iterator.
Wenn ich geschrieben hatte, mit iterator wie dieses, statt:
Und das Ergebnis ist das gleiche wie oben. Der iter ist erschöpft von der Zeit treten wir in die zweite for-Schleife.
Aber das ist eher simpel, was über das etwas komplizierter? Vielleicht war in einer Schleife, warum nicht?
Und wenn es läuft, benutzen wir den iterator auf den string-Typ ist (das ist in iter). Dies wiederum ermöglicht es uns, führen Sie eine for-Schleife, und Ertrag die Ergebnisse, bis wir fertig sind.
So jetzt stellt sich die Frage, was passiert zwischen den Renditen in der "iterator"?
Ist die Antwort, die Funktion wird angehalten auf den Ertrag warten auf den nächsten Aufruf von next().
InformationsquelleAutor der Antwort MadMan2064
Einige zusätzliche details über das Verhalten von
iter()
mit__getitem__
Klassen, die keine eigene__iter__
Methode.Bevor
__iter__
es war__getitem__
. Wenn die__getitem__
arbeitet mitint
s aus0
-len(obj)-1
, danniter()
unterstützt diese Objekte. Es wird der Bau einer neuen iterator, der immer wieder fordert__getitem__
mit0
,1
,2
,...
lange, bis er eineIndexError
, die es wandelt in einStopIteration
.Sehen diese Antwort für weitere details der verschiedenen Möglichkeiten, erstellen einen iterator.
InformationsquelleAutor der Antwort Ethan Furman
Konzept 1
Konzept 2
Konzept 3
In Ihrem Fall
InformationsquelleAutor der Antwort Abhijit
Auszug aus das Python Praxis Buch:
5. Iteratoren & Generatoren
5.1. Iteratoren
Verwenden wir für die Anweisung zum Durchlaufen einer Liste.
Wenn wir es mit einem string, Schleifen über seine Charaktere.
Wenn wir es mit einem Wörterbuch, ist es eine Schleife über die Schlüssel.
Wenn wir es mit einer Datei, ist es eine Schleife über die Zeilen der Datei.
Also es gibt viele Arten von Objekten, die verwendet werden können, mit einer for-Schleife. Diese werden als wiederholenden Objekten.
Gibt es viele Funktionen, die verbrauchen diese iterables.
5.1.1. Die Iteration Protokoll
Die built-in function iter dauert wiederholenden Objekt und gibt einen iterator.
StopIteration
Jeder Zeit rufen wir mit der nächsten Methode auf dem iterator gibt uns das nächste element. Wenn es keine weiteren Elemente mehr, es wird eine StopIteration.
Iteratoren sind als Klassen implementiert. Hier ist ein iterator, der arbeitet wie die eingebaute Funktion xrange.
Den iter Methode ist es, was ein Objekt ist iterierbar. Hinter den kulissen, die das iter-Funktion ruft iter Methode auf das vorliegende Objekt.
Den Rückgabewert iter ist ein iterator. Es sollte eine next-Methode und raise StopIteration, wenn es keine weiteren Elemente mehr.
Probieren Sie es aus:
StopIteration
Viele built-in-Funktionen akzeptieren Iteratoren als Argumente.
In dem oben genannten Fall, der sowohl die durchsuchbar und iterator sind das gleiche Objekt. Beachten Sie, dass die iter Methode zurückgegeben selbst. Es muss nicht der Fall immer.
Wenn beide iteratable und iterator sind das gleiche Objekt, es ist verzehrt in einer einzigen iteration.
5.2. Generatoren
Generatoren vereinfacht die Erstellung von Iteratoren. Ein generator ist eine Funktion, die erzeugt eine Sequenz von Ergebnissen statt von einem einzigen Wert.
Jedes mal, wenn die yield-Anweisung ausgeführt wird, erzeugt die Funktion einen neuen Wert ein.
StopIteration
So ein generator ist auch ein iterator. Sie müssen nicht sorgen zu machen über das iterator-Protokoll.
Dem Wort "generator" ist mißverständlich verwendet, um zu bedeuten, dass beide die Funktion erzeugt wird, und dem, was es erzeugt. In diesem Kapitel werde ich das Wort "generator", dass das generierte Objekt und "generator function" bedeutet, die Funktion, die Sie erzeugt.
Können Sie darüber nachdenken, wie es intern arbeitet?
Wenn ein generator aufgerufen wird, es gibt ein generator-Objekt, ohne auch nur auf den Beginn der Ausführung der Funktion. Bei der nächsten Methode wird das erste mal aufgerufen, startet die Funktion ausgeführt, bis es erreicht yield-Anweisung. Das ergab Wert zurückgegeben, der durch den nächsten Anruf.
Das folgende Beispiel veranschaulicht das Wechselspiel zwischen Rendite und Aufruf der nächsten Methode, auf ein generator-Objekt.
StopIteration
Können sehen, ein Beispiel:
InformationsquelleAutor der Antwort drewteriyaki