Python List Iterator Verhalten und next (Iterator)

147

Erwägen:

>>> lst = iter([1,2,3])
>>> next(lst)
1
>>> next(lst)
2

Das Vorrücken des Iterators erfolgt also erwartungsgemäß durch Mutieren desselben Objekts.

In diesem Fall würde ich erwarten:

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

Um jedes zweite Element zu überspringen: Der Aufruf von nextsollte den Iterator einmal vorrücken, dann sollte der implizite Aufruf der Schleife ihn ein zweites Mal vorrücken - und das Ergebnis dieses zweiten Aufrufs würde zugewiesen i.

Das tut es nicht. Die Schleife druckt alle Elemente in der Liste, ohne sie zu überspringen.

Mein erster Gedanke war, dass dies passieren könnte, weil die Schleife aufruft, iterwas übergeben wird, und dies könnte einen unabhängigen Iterator ergeben - dies ist nicht der Fall, wie wir es getan haben iter(a) is a.

Warum scheint nextder Iterator in diesem Fall nicht voranzukommen?

lvc
quelle

Antworten:

197

Was Sie sehen, ist, dass der Interpreter den Rückgabewert von zurückgibt next()und zusätzlich bei ijeder Iteration gedruckt wird:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0
1
2
3
4
5
6
7
8
9

Dies 0gilt auch für die Ausgabe print(i), 1den Rückgabewert von next(), die vom interaktiven Interpreter usw. wiedergegeben wird. Es gibt nur 5 Iterationen, wobei jede Iteration dazu führt, dass 2 Zeilen in das Terminal geschrieben werden.

Wenn Sie die Ausgabe der next()Dinge zuweisen, funktionieren Sie wie erwartet:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    _ = next(a)
... 
0
2
4
6
8

oder drucken Sie zusätzliche Informationen, um die print()Ausgabe vom interaktiven Interpreter-Echo zu unterscheiden:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print('Printing: {}'.format(i))
...    next(a)
... 
Printing: 0
1
Printing: 2
3
Printing: 4
5
Printing: 6
7
Printing: 8
9

Mit anderen Worten, next()funktioniert wie erwartet, aber da der nächste Wert vom Iterator zurückgegeben wird, der vom interaktiven Interpreter wiedergegeben wird, wird angenommen, dass die Schleife irgendwie über eine eigene Iterator-Kopie verfügt.

Martijn Pieters
quelle
13
Ich war mir dieses Verhaltens des Dolmetschers nicht bewusst. Ich bin froh, dass ich das entdeckt habe, bevor ich viel Zeit verloren habe, mich darüber zu wundern, während ich ein echtes Problem gelöst habe.
Brandizzi
5
... *stirbt*. Das Schlimmste ist, ich kann mich daran erinnern, dass ich vor einer Woche jemandem genau dieses Dolmetscherverhalten gegenüber erwähnt habe.
lvc
interessant. Ich habe versucht, i in a: next (a); i zu drucken und dachte, ich würde zu 1 springen und 1,3,5,7,9 drucken. Trotzdem ist es 0,2,4,6,8. Warum?
user2290820
3
iwurde bereits vergeben. next(a)bedeutet, dass die nächste Iteration 2zugewiesen wird i, dann gehen Sie awieder weiter, drucken iusw.
Martijn Pieters
1
Dies funktioniert nicht, wenn n ungerade ist - StopIterationexcepetio n wird ausgelöst, wenn next(a)es aufgerufen wird, nachdem die Liste exaustiert wurde.
Raf
13

Was passiert, ist, dass next(a)der nächste Wert von a zurückgegeben wird, der auf der Konsole gedruckt wird, weil er nicht betroffen ist.

Sie können eine Variable mit diesem Wert beeinflussen:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    b=next(a)
...
0
2
4
6
8
njzk2
quelle
8

Ich finde die vorhandenen Antworten etwas verwirrend, weil sie nur indirekt auf das Wesentliche im Codebeispiel hinweisen: Sowohl * das "print i" als auch das "next (a)" bewirken, dass ihre Ergebnisse gedruckt werden.

Da sie alternierende Elemente der ursprünglichen Sequenz drucken und es unerwartet ist, dass die Anweisung "next (a)" gedruckt wird, sieht es so aus, als ob die Anweisung "print i" alle Werte druckt.

In diesem Licht wird klarer, dass das Zuweisen des Ergebnisses von "next (a)" zu einer Variablen das Drucken ihres Ergebnisses verhindert, so dass nur die alternativen Werte gedruckt werden, die die "i" -Schleifenvariable druckt. In ähnlicher Weise wird es auch deutlich, wenn die "print" -Anweisung etwas Besonderes hervorruft.

(Eine der vorhandenen Antworten widerlegt die anderen, da bei dieser Antwort der Beispielcode als Block ausgewertet wird, sodass der Interpreter die Zwischenwerte für "next (a)" nicht meldet.)

Das Verführerische bei der Beantwortung von Fragen ist im Allgemeinen, explizit zu sagen, was offensichtlich ist, sobald Sie die Antwort kennen. Es kann schwer fassbar sein. Ebenso kritisieren Sie Antworten, sobald Sie sie verstanden haben. Es ist interessant...

klm
quelle
2

Mit Ihrem Python / Computer stimmt etwas nicht.

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

>>> 
0
2
4
6
8

Funktioniert wie erwartet.

Getestet in Python 2.7 und in Python 3+. Funktioniert in beiden richtig

Inbar Rose
quelle
5
Ich bekomme das gleiche Ergebnis wie @lvc (nur auf IDLE, aber wenn es als Skript ausgeführt wird, bekomme ich dies))
Jamylak
3
@Inbar Rose Nur wenn Sie als Skript ausgeführt werden.
Quintec
1
Es ist das Verhalten beim Einfügen von Code über eine interaktive Shell. Wenn die Funktion einen Wert zurückgibt, der nicht verwendet wird, druckt der Interpreter ihn als Debug-Ausgabe in die Shell
Reishin,
2

Für diejenigen, die immer noch nicht verstehen.

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0 # print(i) printed this
1 # next(a) printed this
2 # print(i) printed this
3 # next(a) printed this
4 # print(i) printed this
5 # next(a) printed this
6 # print(i) printed this
7 # next(a) printed this
8 # print(i) printed this
9 # next(a) printed this

Wie andere bereits gesagt haben, nexterhöht sich der Iterator erwartungsgemäß um 1. Das Zuweisen des zurückgegebenen Werts zu einer Variablen ändert das Verhalten nicht auf magische Weise.

Wesley
quelle
1

Es verhält sich wie gewünscht, wenn es als Funktion aufgerufen wird:

>>> def test():
...     a = iter(list(range(10)))
...     for i in a:
...         print(i)
...         next(a)
... 
>>> test()
0
2
4
6
8
burmer
quelle