Verwechselt mit Python-Listen: Sind sie oder sind sie keine Iteratoren?

78

Ich studiere Alex Martelis Python auf den Punkt gebracht und das Buch schlägt vor, dass jedes Objekt, das eine next()Methode hat, ein Iterator ist (oder zumindest als Iterator verwendet werden kann) . Es wird auch vorgeschlagen, dass die meisten Iteratoren durch implizite oder explizite Aufrufe einer aufgerufenen Methode erstellt werden iter.

Nachdem ich dies in dem Buch gelesen hatte, verspürte ich den Drang, es zu versuchen. Ich habe einen Python 2.7.3-Interpreter gestartet und dies getan:

>>> x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> for number in range(0, 10):
...     print x.next()

Das Ergebnis war jedoch folgendes:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AttributeError: 'list' object has no attribute 'next'

In Verwirrung versuchte ich, die Struktur des x-Objekts über zu untersuchen, dir(x)und bemerkte, dass es ein __iter__Funktionsobjekt hatte. Also habe ich herausgefunden, dass es als Iterator verwendet werden kann, solange es diese Art von Schnittstelle unterstützt.

Als ich es erneut versuchte, diesmal etwas anders, versuchte ich Folgendes:

>>> _temp_iter = next(x)

Ich habe diesen Fehler erhalten:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list object is not an iterator

Aber wie kann eine Liste KEIN Iterator sein, da sie diese Schnittstelle zu unterstützen scheint und im folgenden Kontext durchaus als eine verwendet werden kann:

>>> for number in x:
...     print x

Könnte mir jemand helfen, dies in meinem Kopf zu klären?

NlightNFotis
quelle

Antworten:

103

Sie sind iterierbar , aber keine Iteratoren . Sie können übergeben werden iter(), um entweder implizit (z. B. über for) oder explizit einen Iterator für sie zu erhalten , aber sie sind keine Iteratoren an und für sich.

Ignacio Vazquez-Abrams
quelle
11
Beachten Sie, dass alle Iteratoren (die sich gut benehmen) auch iterierbar sind - sie nextkehren einfach zurück self, sodass Sie iter(iter(iter(iter(x))))das Gleiche wie aufrufen und abrufen können iter(x). Aus diesem Grund forfunktioniert es sowohl mit Iterables als auch mit Iteratoren ohne Typ-Sniffing (ohne Berücksichtigung von Leistungsoptimierungen).
13
@ Delnan Ich denke du meintest, dass "ihre itereinfach zurück self".
Lauritz V. Thaulow
Die nächste Frage ist natürlich; Warum sollen sie keine Iteratoren sein?
Gerrit
2
@gerrit: Weil Iteratoren keinen Direktzugriff unterstützen.
Ignacio Vazquez-Abrams
1
@ IgnacioVazquez-Abrams Ist "nicht unterstützen" eine Anforderung? Ich dachte, dass Anforderungen / Verträge normalerweise positiv sind und dass man immer noch X "sein" kann (im Sinne von: zu allem fähig sein, wozu X fähig ist), während man Fähigkeiten hat, die X nicht hat.
Gerrit
26

Sie müssen die Liste zuerst in einen Iterator konvertieren, indem Sie Folgendes verwenden iter():

In [7]: x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [8]: it=iter(x)

In [9]: for i in range(10):
    it.next()
   ....:     
   ....:     
Out[10]: 0
Out[10]: 1
Out[10]: 2
Out[10]: 3
Out[10]: 4
Out[10]: 5
Out[10]: 6
Out[10]: 7
Out[10]: 8
Out[10]: 9

In [12]: 'next' in dir(it)
Out[12]: True

In [13]: 'next' in dir(x)
Out[13]: False

Überprüfen, ob ein Objekt ein Iterator ist oder nicht:

In [17]: isinstance(x,collections.Iterator)
Out[17]: False

In [18]: isinstance(x,collections.Iterable)
Out[18]: True

In [19]: isinstance(it,collections.Iterable) 
Out[19]: True

In [20]: isinstance(it,collections.Iterator)
Out[20]: True
Ashwini Chaudhary
quelle
22

Nur für den Fall, dass Sie sich nicht sicher sind, was der Unterschied zwischen Iterables und Iteratoren ist. Ein Iterator ist ein Objekt, das einen Datenstrom darstellt. Es implementiert das Iteratorprotokoll:

  • __iter__ Methode
  • next Methode

Wiederholte Aufrufe der next () -Methode des Iterators geben aufeinanderfolgende Elemente im Stream zurück. Wenn keine Daten mehr verfügbar sind, ist das Iteratorobjekt erschöpft und alle weiteren Aufrufe der next () -Methode lösen StopIteration erneut aus.

Auf der anderen Seite implementieren iterierbare Objekte die __iter__Methode, die beim Aufruf einen Iterator zurückgibt, der mehrere Durchgänge über ihre Daten ermöglicht. Iterierbare Objekte können wiederverwendet werden. Sobald sie erschöpft sind, können sie erneut wiederholt werden. Sie können mit der iterFunktion in Iteratoren konvertiert werden .

Wenn Sie also eine Liste (iterierbar) haben, können Sie Folgendes tun:

>>> l = [1,2,3,4]
>>> for i in l:
...     print i,
1 2 3 4
>>> for i in l:
...     print i,
 1 2 3 4

Wenn Sie Ihre Liste in einen Iterator konvertieren:

>>> il = l.__iter__()  # equivalent to iter(l)
>>> for i in il:
...     print i,
 1 2 3 4
>>> for i in il:
...     print i,
>>> 
Vicent
quelle
7

List ist kein Iterator, aber list enthält ein Iteratorobjekt. __iter__Wenn Sie also versuchen, die for-Schleife in einer beliebigen Liste zu verwenden, ruft die __iter__Methode loop auf und ruft das Iteratorobjekt ab. Anschließend wird die Methode next () der Liste verwendet.

x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
it = x.__iter__()

itEnthält jetzt ein Iterator-Objekt, xdas Sie verwenden können, it.next()bis die StopIteration-Ausnahme ausgelöst wird

Kaushal
quelle
3
Was zu…AttributeError: 'list' object has no attribute 'iter'
E-Sushi
Ja, ich weiß, dass es kein Iter-Attribut gibt. Sie müssen vor und nach der Iter-Methode 2 Unterstriche setzen. Der __iter__Stapelüberlauf konvertiert ihn in Fettdruck, indem der in meiner Antwort erwähnte Unterstrich ersetzt wird. Ich war mir dieser Sache nicht bewusst
Kaushal
In Python3 it.next()erhöht AttributeError: 'list_iterator' object has no attribute 'next'. Stattdessen gibt esnext(it)