为什么xrange能够回到Python的开头?

2024-05-26 22:59:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我遇到了来自Most pythonic way of counting matching elements in something iterable的代码

r = xrange(1, 10)
print sum(1 for v in r if v % 2 == 0) # 4
print sum(1 for v in r if v % 3 == 0) # 3

r迭代一次。然后再次迭代。我想如果一个迭代器被消费了,那么它就结束了,不应该再迭代了。在

生成器表达式只能迭代一次:

^{pr2}$

列举(L):

r = enumerate(mylist)

以及文件对象:

f = open(myfilename, 'r')

为什么xrange的行为有所不同?在


Tags: ofinmostforifelementspythoniciterable
3条回答

因为通过调用xrange()生成的xrange对象指定了一个__iter__,该对象在每次迭代时都提供其自身的唯一版本(实际上是一个单独的rangeiterator对象)。在

>>> x = xrange(3)
>>> type(x)
<type 'xrange'>
>>> i = x.__iter__()
>>> type(i)
<type 'rangeiterator'>

因为xrange不返回生成器。它返回一个xrange object。在

>>> type(xrange(10))
<type 'xrange'>

除了重复迭代之外,xrange对象还支持生成器不喜欢索引的其他功能:

^{pr2}$

它们还有一个长度:

^{3}$

它们可以逆转:

>>> list(reversed(xrange(10)))
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

简而言之,xrange对象实现了完整的sequenceinterface

>>> import collections
>>> isinstance(xrange(10), collections.Sequence)
True

他们只是在不消耗大量内存的情况下做这件事。在

还要注意,在Python3中,range返回的range对象具有所有相同的属性。在

如果你只知道它是一个迭代器,那么在general中,你必须假设你只能迭代一次。这并不意味着每个迭代器只能使用一次,只是每个迭代器至少可以消耗一次。一个明显的例子是列表和其他序列支持这个接口。在

正如senderle和Amber所解释的那样,您通过调用xrange获得的特定迭代器碰巧被实现为可以对它们进行多次迭代。在

迭代器可能在迭代器之后耗尽。这是因为许多迭代器(如生成器、文件遍历等)如果必须支持任意多个遍历,则很难实现,或者消耗更多内存或运行速度慢得多,而且通常这种功能甚至不会被使用。所以如果迭代器必须支持任意多个遍历,那么这些东西可能就不是迭代器了。在

长话短说,如果您编写的代码在任意未知迭代器上运行,那么您假设它只能被遍历一次,而且如果有人给您的对象支持的比您所需的功能更多,则无所谓。如果您知道一些关于迭代器的附加信息(比如它也是一个序列,或者甚至是一个xrange对象),那么您可以根据需要编写代码来使用它。在

相关问题 更多 >

    热门问题