【问题标题】:Python bug? Lazy objects have hidden state蟒蛇错误?惰性对象具有隐藏状态
【发布时间】:2013-01-03 10:18:49
【问题描述】:

考虑一下(Python 3.3):

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

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

如果将列表替换为settupledict,也会发生同样的情况。如果你用mapfilter 替换enumerate 对象也会发生这种情况,但奇怪的是,如果你用range 替换它就不会。

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

【问题讨论】:

  • 我真的希望这两个打印调用打印不同的东西。

标签: python lazy-evaluation enumerate


【解决方案1】:

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() 确实 not 返回一个迭代器。它返回一个range object,它代表一个内存高效的数字序列;只需要存储开始、结束和步幅,其他所有内容都可以从这 3 个点推导出来。

【讨论】:

    【解决方案2】:

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

    一个值得注意的例外是尝试多次迭代的代码 通过。 ...用迭代器尝试这个只会返回相同的结果 上一次迭代过程中使用的迭代器对象已用尽,使得 它看起来像一个空容器。

    【讨论】:

    • 啊,我明白了。我将迭代器与可迭代对象混淆了。迭代器有点可迭代,但只有一次。 :-) 这对于我正在编写的代码来说太糟糕了......我想没有什么好的方法可以“重绕”迭代器?
    • 如果你想倒回一个迭代器,那么你应该将它转换为一个列表并使用它。如果迭代器太大(甚至无限)而无法转换为列表,则没有通用的方法来回退它。
    • 你可能会建立一个结构,只允许你“后退”一次或两次。如果您愿意,可以有限倒带
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-24
    • 1970-01-01
    • 2018-08-26
    • 1970-01-01
    • 2016-10-17
    相关资源
    最近更新 更多