与 python 列表混淆: 它们是迭代器还是不是迭代器?

我正在学习 亚历克斯 · 马泰利的《果壳里的巨蟒》,这本书建议任何具有 next()方法的对象都是(或者至少可以用作) 迭代器。它还表明,大多数迭代器都是通过对称为 iter的方法的隐式或显式调用构建的。

看完这本书后,我很想尝试一下。我启动了一个 python 2.7.3解释程序,并执行了以下操作:

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

然而结果是这样的:

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

在混乱中,我试图通过 dir(x)研究 x 对象的结构,我注意到它有一个 __iter__函数对象。所以我发现它可以用作迭代器,只要它支持那种类型的接口。

所以当我再次尝试,这次稍微不同,尝试这样做:

>>> _temp_iter = next(x)

我得到了这个错误:

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

但是一个列表怎么可能不是迭代器,因为它看起来支持这个接口,并且当然可以在下面的上下文中作为一个迭代器使用:

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

有没有人能帮我理清思路?

60513 次浏览

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

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.

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

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

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__()