与Python列表混淆:他们还是不是迭代器?

我正在研究Alex Marteli的Python in the Nutshell ,本书指出任何具有next()方法的对象都是(或者至less可以用作) 迭代器 。 它也表明大多数迭代器是通过对称为iter的方法的隐式或显式调用来构build的。

在读完这本书之后,我觉得有尝试的冲动。 我启动了一个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__函数对象。 所以我发现它可以用作迭代器,只要它支持这种types的接口。

所以当我再次尝试时,这次稍微不同,试图做到这一点:

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

有人能帮我澄清一下吗?

它们是可迭代的 ,但它们不是迭代器 。 他们可以被传递给iter()以隐式地(例如通过for )或者显式地获得它们的迭代器,但是它们本身并不是迭代器。

您需要先使用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 

检查对象是否是迭代器:

 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 

以防万一您对迭代器和迭代器之间的差异感到困惑。 迭代器是表示数据stream的对象。 它实现了迭代器协议:

  • __iter__方法
  • next方法

重复调用迭代器的next()方法返回stream中的连续项。 当没有更多的数据可用时,迭代器对象将耗尽,并且对next()方法的任何进一步调用只会再次引发StopIteration。

另一方面,可迭代对象实现__iter__方法,当被调用时返回一个迭代器,允许多次传递数据。 可重用对象是可重用的,一旦耗尽,可以重复使用。 它们可以使用iter函数转换为迭代器。

所以如果你有一个列表(可迭代),你可以这样做:

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

如果你把你的列表转换成一个迭代器:

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

List不是迭代器,但列表包含一个迭代器对象__iter__所以当你尝试在任何列表上使用for循环,for循环调用__iter__方法并获取迭代器对象,然后使用列表的next()方法。

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

现在it包含x迭代器对象,您可以使用它作为it.next()直到引发StopIterationexception