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


78

我正在研究Alex Marteli的《 Nutshell》中的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'

在混乱中,我尝试通过研究x对象的结构,dir(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

有人可以帮我澄清一下这个想法吗?

Answers:


103

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


11
请注意,所有迭代器(行为良好)也是可迭代的-它们next只是返回self,因此您可以调用iter(iter(iter(iter(x))))并获得与相同的东西iter(x)。这就是为什么for在不进行类型嗅探的情况下(而不考虑性能优化)使用迭代器和迭代器的原因。

13
@delnan我想你的意思是“他们iter只是返回self”。
Lauritz V. Thaulow 2012年

当然,下一个问题是:为什么将它们设计为不迭代器?
Gerrit '16

2
@gerrit:因为迭代器不支持随机访问。
伊格纳西奥·巴斯克斯·阿布拉姆斯

1
@ IgnacioVazquez-Abrams是否“不支持”要求?我认为需求/合同通常是积极的,并且人们仍然可以“成为” X(从某种意义上说:有能力X具备的一切能力)而拥有X所没有的能力。
gerrit

26

您需要先使用将列表转换为迭代器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

22

以防万一您对可迭代与迭代器之间的区别感到困惑。迭代器是代表数据流的对象。它实现了迭代器协议:

  • __iter__ 方法
  • next 方法

重复调用迭代器的next()方法将返回流中的后续项。当没有更多数据可用时,迭代器对象将用尽,并且对其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,
>>> 

7

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

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

现在it包含迭代器对象,在引发StopIteration异常之前x,可以将其用作it.next()


3
结果导致…AttributeError: 'list' object has no attribute 'iter'
e-sushi

是的,我知道没有iter属性,您必须在iter方法前后放置2个下划线__iter__,堆栈溢出通过替换我在答案中提到的下划线将其转换为粗体字符。我没有意识到这件事
Kaushal,2015年

在python3中it.next()引发AttributeError: 'list_iterator' object has no attribute 'next'。而是有next(it)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.