【问题标题】:Why is the range object "not an iterator"? [duplicate]为什么范围对象“不是迭代器”? [复制]
【发布时间】:2014-03-15 06:12:21
【问题描述】:

我写了这个并期待0

>>> x = range(20)
>>> next(x)

相反,我得到了:

TypeError: 'range' 对象不是迭代器

但我以为它是发电机?

最初的答案与我最初对自己说的相同:它是可迭代的,而不是交互器。但是,如果两者都只是生成器,那并不能解释为什么会这样:

>>> x = (i for i in range(30))
>>> next(x)
0

【问题讨论】:

标签: python python-3.x generator


【解决方案1】:

范围对象是可迭代的。但是,它不是 迭代器

要获取迭代器,需要先调用iter()

>>> r=range(5,15)
>>> next(iter(r))
5
>>> next(iter(r))
5
>>> next(iter(r))
5
>>> next(iter(r))
5
>>> i=iter(r)
>>> next(i)
5
>>> next(i)
6
>>> next(i)
7
>>> next(i)
8
>>> iter(r)
<range_iterator object at 0x10b0f0630>
>>> iter(r)
<range_iterator object at 0x10b0f0750>
>>> iter(r)
<range_iterator object at 0x10b0f0c30>

编辑:但请注意不要在每次调用next() 时都调用iter()。它在索引 0 处创建一个新的迭代器。

【讨论】:

  • 我一开始也是这么告诉自己的。但是,为什么这会起作用:next( (i for i in range(30) ),因为那是生成器表达式?实际上,让我将这个添加到问题中。
  • “它确实是一个生成器”——不,它不是。
  • @Aerovista:因为生成器表达式的计算结果是迭代器?
  • @NPE tldr;正如我所想,生成器可以被视为迭代器。所以这些信息是不相关的——正确的答案是 range() 对象是不可变的和特殊的,实际上不是简单的生成器。
  • @user2357112:哦,我没有打电话。这解释了它。漫长的一天,我要睡觉了。
【解决方案2】:

range 返回一个可迭代的,而不是一个迭代器。它可以在需要迭代时制作迭代器。 它不是生成器。

生成器表达式的计算结果为迭代器(因此也是可迭代的)。

【讨论】:

  • 请注意,您可以通过调用 iter() 从这个可迭代对象中获得一个迭代器。然后,您可以在 iter(range(...)) 的结果上调用 next() 内置函数。这很令人困惑,但这只是当您深入了解该语言时所学到的东西之一。请注意,for 循环会隐式调用 iter(expression) 一次,然后在每次通过循环时调用 next(results_from_iter)。
【解决方案3】:

next 内置函数调用 __next__ 钩子方法。所以,range 对象有一个明确定义的__iter__,但没有明确定义的__next__

iterable 对象定义了__iter__iterator 对象定义了__next__(通常使用__iter__ 方法,它只返回self)。

【讨论】:

    【解决方案4】:

    这是因为next函数调用了传入对象的next方法。

    next(...)
        x.next() -> the next value, or raise StopIteration
    

    listiterators 和 generators 都有 next 方法。

    >>> iter(range(1)).__class__.next
    <slot wrapper 'next' of 'listiterator' objects>
    >>> iter(x for x in range(1)).__class__.next
    <slot wrapper 'next' of 'generator' objects>
    

    但是list 没有它。这就是它引发该异常的原因。

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

    next 不太关心它传递的对象是否是迭代器。

    >>> class Foo():
    ...     def next(self):
    ...             return "foo"
    ... 
    >>> foo = Foo()
    >>> next(foo)
    'foo'
    >>> next(foo)
    'foo'
    

    但添加next 方法并不一定使其成为集合/序列/可迭代。

    >>> class Foo():
    ...     def next(self):
    ...             return "Foo"
    >>> [x for x in Foo()]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: iteration over non-sequence
    >>> iter(Foo())
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: iteration over non-sequence
    

    但是添加__iter__ 方法使其成为一个。

    >>> class Foo():
    ...     def next(self):
    ...             return "Foo"
    ...     def __iter__(self): return self
    ... 
    >>> [x for x in Foo()]
    ^CTraceback (most recent call last):
      File "<stdin>", line 1, in <module>
    KeyboardInterrupt
    >>> iter(Foo())
    <__main__.Foo instance at 0x7fd77307c488>
    

    next 似乎具有与list 相关的内置智能。

    >>> class Foo():
    ...     pass
    ... 
    >>> foo = Foo()
    >>> next(foo)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: instance has no next() method
    >>> next(range(20))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: list object is not an iterator
    

    【讨论】:

      猜你喜欢
      • 2020-12-20
      • 1970-01-01
      • 2020-10-14
      • 1970-01-01
      • 2018-08-16
      • 1970-01-01
      相关资源
      最近更新 更多