如果range()是Python 3.3中的生成器,为什么不能在范围上调用next()?


84

也许我已经成为网络错误信息的受害者,但我认为更可能是我误解了一些信息。根据到目前为止的知识,range()是一个生成器,并且生成器可以用作迭代器。但是,此代码:

myrange = range(10)
print(next(myrange))

给我这个错误:

TypeError: 'range' object is not an iterator

我在这里想念什么?我期望它打印0,并前进到中的下一个值myrange。我是Python的新手,所以请接受我对这个基本问题的歉意,但在其他任何地方都找不到很好的解释。


2
请参见stackoverflow.com/q/13054057/395760,以了解迭代器和可以循环迭代的事物之间的区别for

1
说生成器是可迭代的,而不是迭代器是正确的吗?
杰夫

4
@Jeffiter可迭代对象是可用于获取迭代器的对象。迭代器是可以使用进行迭代的对象next。生成器是迭代器的一类(生成器函数和生成器表达式)。至少那是我的想法……
Oleh Prypin 2012年

Answers:


109

range是一类不变的可迭代对象。可以将它们的迭代行为与lists进行比较:您不能next直接调用它们;您必须使用来获得迭代器iter

所以不,range不是发电机。

您可能会想,“他们为什么不直接迭代呢?”?好吧,ranges具有一些有用的属性,而这是不可能的:

  • 它们是不可变的,因此可以用作字典键。
  • 他们有startstopstep属性(因为Python 3.3),countindex方法,它们支持inlen__getitem__操作。
  • 您可以range多次迭代相同的对象。

>>> myrange = range(1, 21, 2)
>>> myrange.start
1
>>> myrange.step
2
>>> myrange.index(17)
8
>>> myrange.index(18)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 18 is not in range
>>> it = iter(myrange)
>>> it
<range_iterator object at 0x7f504a9be960>
>>> next(it)
1
>>> next(it)
3
>>> next(it)
5

11
range对象的另一个不错的功能是它们具有一种__contains__可用于测试值是否在范围内的方法:5 in range(10) => True
kindall 2012年

谢谢你的回答; 现在这很有意义。在接受您的答案之前,我唯一要清除的是斜体字的注释,该注释表示页面下半部分的内容,指出“在Python 3中range()是生成器”。这是完全不正确的吗?
杰夫

3
@Jeff严格来说,是的,这是错误的。该注释的作者可能意味着在Python 3中range惰性的(与Python 2相比,Python 2仅是返回列表的函数)。
Oleh Prypin 2012年

6
另外:range(0,10,3)[3]9 in range(0,10,3)。范围几乎是一个懒惰的列表。
Lennart Regebro 2012年

2
@ user3079275“直接可迭代”是用词不当,实际上是“迭代器”。迭代器具有内部状态,因此根据定义是可变的。“可迭代”是可以生成迭代器的对象,无论它是否可变。甚至可变对象本身也通常不是迭代器,而是以可重用的方式生成迭代器(例如,您可以使用两个迭代器在两个不同的位置分别迭代同一列表)。
Oleh Prypin '17
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.