2

考虑一下(Python 3.3):

a=enumerate([2,3,5])
print(list(a))
print(list(a))

你真的希望两个打印调用打印不同的东西吗?我也不。

如果将 list 替换为set,tuple或,也会发生同样的事情dict。如果你用or替换enumerateobject也会发生这种情况,但奇怪的是,如果你用 替换它就不会。mapfilterrange

也许这是一个特点。但这非常令人惊讶,没有记录(至少我无法找到任何关于它的信息),并且不一致(范围的工作方式不同)。你怎么看?

4

2 回答 2

7

enumerate()返回一个迭代器,其他调用也是如此。您只能循环遍历一个迭代器;然后用尽。

您可以使用生成器函数自己创建这样的迭代器:

def somelist_generator():
    somelist = [1, 2, 3]
    while somelist:
        yield somelist.pop()

如果你要循环somelist_generator(),列表somelist将被清空。你只能这样做一次,因为.pop()删除元素:

>>> it = somelist_generator()
>>> for i in it:
...     print(i)
... 
3
2
1
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

next()调用尝试从it迭代器中获取另一个值;它已经是空的,因此StopIteration引发了异常。该异常表明没有更多元素要获取,这就是为什么您第二次尝试从迭代器获取任何内容时最终得到一个空列表的原因:

>>> list(it)
[]

range()不返回迭代器相反,它返回一个范围对象,该对象代表一个内存有效的数字序列;只需要存储开始、结束和步幅,其他所有内容都可以从这 3 个点得出。

于 2013-01-03T10:19:51.367 回答
2

该行为记录在http://docs.python.org/3/glossary.html#term-iterator

一个值得注意的例外是尝试多次迭代的代码。...使用迭代器尝试此操作只会返回与上一次迭代过程中使用的相同的耗尽迭代器对象,使其看起来像一个空容器。

于 2013-01-03T10:26:26.957 回答