94

I am studying Alex Marteli's Python in a Nutshell and the book suggests that any object that has a next() method is (or at least can be used as) an iterator. It also suggests that most iterators are built by implicit or explicit calls to a method called iter.

After reading this in the book, I felt the urge to try it. I fired up a python 2.7.3 interpreter and did this:

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

However the result was this:

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

In confusion, I tried to study the structure of the x object via dir(x) and I noticed that it had a __iter__ function object. So I figured out that it can be used as an iterator, so long as it supports that type of interface.

So when I tried again, this time slightly differently, attempting to do this:

>>> _temp_iter = next(x)

I got this error:

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

But how can a list NOT be an iterator, since it appears to support this interface, and can be certainly used as one in the following context:

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

Could someone help me clarify this in my mind?

NlightNFotis
  • 9,559
  • 5
  • 43
  • 66

5 Answers5

118

They are iterable, but they are not iterators. They can be passed to iter() to get an iterator for them either implicitly (e.g. via for) or explicitly, but they are not iterators in and of themselves.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • 12
    Note that all iterators (which are well-behaved) are also iterable -- their `next` simply returns `self`, so you can call `iter(iter(iter(iter(x))))` and get the same thing as `iter(x)`. This is why `for` works with both iterables and iterators without type sniffing (well, disregarding performance optimizations). –  Oct 24 '12 at 17:07
  • 14
    @delnan I guess you meant that "their `iter` simply returns `self`". – Lauritz V. Thaulow Oct 24 '12 at 17:40
  • 2
    The next question is, of course; *why* are they designed to not be iterators? – gerrit Jul 06 '16 at 17:07
  • 3
    @gerrit: Because iterators do not support random access. – Ignacio Vazquez-Abrams Jul 06 '16 at 19:44
  • 1
    @IgnacioVazquez-Abrams Is "do not support" a requirement? I thought requirements / contracts were usually positive, and that one can still "be" X (in the sense of: be capable of everything X is capable of) while having capabilities that X doesn't have. – gerrit Jul 07 '16 at 00:32
  • i am so confused, python list class singnature: class list(object): clearly list doesn't inherits iterable, but i know it is a iterable... how this works? anyone call explain plz – Junchen Liu Jul 14 '19 at 22:32
29

Just in case you are confused about what the difference between iterables and iterators is. An iterator is an object representing a stream of data. It implements the iterator protocol:

  • __iter__ method
  • next method

Repeated calls to the iterator’s next() method return successive items in the stream. When no more data is available the iterator object is exhausted and any further calls to its next() method just raise StopIteration again.

On the other side iterable objects implement the __iter__ method that when called returns an iterator, which allows for multiple passes over their data. Iterable objects are reusable, once exhausted they can be iterated over again. They can be converted to iterators using the iter function.

So if you have a list (iterable) you can do:

>>> 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

If you convert your list into an iterator:

>>> il = l.__iter__()  # equivalent to iter(l)
>>> for i in il:
...     print i,
 1 2 3 4
>>> for i in il:
...     print i,
>>> 
Vicent
  • 5,322
  • 2
  • 28
  • 36
28

You need to convert list to an iterator first using 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

checking whether an object is iterator or not:

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
  • 244,495
  • 58
  • 464
  • 504
8

List is not iterator but list contains an iterator object __iter__ so when you try to use for loop on any list, for loop calls __iter__ method and gets the iterator object and then it uses next() method of list.

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

Now it contains iterator object of x which you can use as it.next() until StopIteration exception is thrown

Huy Vo
  • 2,418
  • 6
  • 22
  • 43
Kaushal
  • 409
  • 5
  • 8
  • 3
    Which results in… `AttributeError: 'list' object has no attribute 'iter'` – e-sushi Aug 07 '14 at 04:36
  • yes I know there is no iter attribute, you have to put 2 underscore before and after iter method `__iter__`, Stack overflow is converting it to bold character by replacing the underscore i mentioned in my answer. I was unaware of this thing – Kaushal Apr 07 '15 at 07:37
  • 1
    In python3 `it.next()` raises `AttributeError: 'list_iterator' object has no attribute 'next'`. Instead there is `next(it)` –  Sep 23 '16 at 20:47
0

There are already good answers to it about list being an iterable but not iterator. In python version > 3.0, use the following

a = [1, 2, 3]
b = iter(a)
b.__next__()
Tutankhamun
  • 119
  • 5