【问题标题】:Confused with python lists: are they or are they not iterators?对 python 列表感到困惑:它们是还是不是迭代器?
【发布时间】:2012-10-14 18:41:39
【问题描述】:

我正在研究Alex Marteli's Python in a Nutshell,这本书建议任何具有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

有人可以帮我澄清一下吗?

【问题讨论】:

    标签: python list iterator


    【解决方案1】:

    关于 list 是一个可迭代但不是迭代器的问题已经有了很好的答案。 在python版本> 3.0,使用以下

    a = [1, 2, 3]
    b = iter(a)
    b.__next__()
    

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 这会导致……AttributeError: 'list' object has no attribute 'iter'
      • 是的,我知道没有 iter 属性,您必须在 iter 方法 __iter__ 之前和之后放置 2 个下划线,堆栈溢出通过替换我在回答中提到的下划线将其转换为粗体字符。我不知道这件事
      • 在 python3 中 it.next() 引发 AttributeError: 'list_iterator' object has no attribute 'next'。取而代之的是next(it)
      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

          • 请注意,所有迭代器(表现良好)也是可迭代的——它们的next 只返回self,因此您可以调用iter(iter(iter(iter(x)))) 并得到与iter(x) 相同的东西.这就是为什么 for 可以在没有类型嗅探的情况下同时使用可迭代对象和迭代器(好吧,忽略性能优化)。
          • @delnan 我猜你的意思是“他们的iter 只是返回self”。
          • 下一个问题当然是; 为什么它们被设计成不是迭代器?
          • @gerrit:因为迭代器不支持随机访问。
          • @IgnacioVazquez-Abrams “不支持”是一项要求吗?我认为要求/合同通常是积极的,并且一个人仍然可以“成为”X(在某种意义上:能够胜任 X 能够胜任的一切),同时拥有 X 所没有的能力。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-20
          • 1970-01-01
          • 1970-01-01
          • 2016-12-27
          • 1970-01-01
          • 2010-10-29
          相关资源
          最近更新 更多