我遇到了来自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的行为有所不同?在
因为通过调用
xrange()
生成的xrange
对象指定了一个__iter__
,该对象在每次迭代时都提供其自身的唯一版本(实际上是一个单独的rangeiterator
对象)。在因为
xrange
不返回生成器。它返回一个xrange object。在除了重复迭代之外,
^{pr2}$xrange
对象还支持生成器不喜欢索引的其他功能:它们还有一个长度:
^{3}$它们可以逆转:
简而言之,
xrange
对象实现了完整的sequenceinterface:他们只是在不消耗大量内存的情况下做这件事。在
还要注意,在Python3中,
range
返回的range
对象具有所有相同的属性。在如果你只知道它是一个迭代器,那么在general中,你必须假设你只能迭代一次。这并不意味着每个迭代器只能使用一次,只是每个迭代器至少可以消耗一次。一个明显的例子是列表和其他序列支持这个接口。在
正如senderle和Amber所解释的那样,您通过调用
xrange
获得的特定迭代器碰巧被实现为可以对它们进行多次迭代。在迭代器可能在迭代器之后耗尽。这是因为许多迭代器(如生成器、文件遍历等)如果必须支持任意多个遍历,则很难实现,或者消耗更多内存或运行速度慢得多,而且通常这种功能甚至不会被使用。所以如果迭代器必须支持任意多个遍历,那么这些东西可能就不是迭代器了。在
长话短说,如果您编写的代码在任意未知迭代器上运行,那么您假设它只能被遍历一次,而且如果有人给您的对象支持的比您所需的功能更多,则无所谓。如果您知道一些关于迭代器的附加信息(比如它也是一个序列,或者甚至是一个xrange对象),那么您可以根据需要编写代码来使用它。在
相关问题 更多 >
编程相关推荐