【问题标题】:How to nicely progress an iterator until it's empty in Python?如何很好地推进迭代器,直到它在 Python 中为空?
【发布时间】:2022-01-19 13:32:39
【问题描述】:

如果我有一个迭代器foo 和一个函数progress 可以任意推进它(但保证它永远不会引发StopIteration),我如何继续调用progress 直到foo是空的吗?

看起来iter([]) 是真的。

这是我最好的尝试:

from itertools import islice
import copy

# Let's say I can't touch this function.
def progress(xs):
    islice(xs, 1) # or some other arbitrary value.

foo = iter(a_list)
while list(copy.copy(foo)): # ????
    progress(foo)

【问题讨论】:

  • 能否提供一个更完整的代码示例,好吗?如果不定义 foo 是什么以及 progress 如何影响它,就很难理解您想要实现的目标。
  • 如果你想把foo 的内容放在一个列表中直到foo 用完,那么就做mylist = list(foo)。否则,您需要更清楚地解释您要做什么。
  • 我喜欢这个问题,但它仍然含糊不清。也许您发布了一些 progress 究竟做了什么的例子?
  • Python 中迭代器的定义是:“一个迭代器对象实现了__next__,它期望返回返回它的可迭代对象的下一个元素,并在没有时引发 StopIteration 异常更多元素可用。”因此,如果您的 progress() 函数从不尝试获取超出迭代器末尾的项目,那么当调用它并且 foo 为空时它会做什么?
  • 好点。我在描述中澄清了:progress 使用itertools.islice,看来这很重要。抱歉不清楚。

标签: python iterator itertools


【解决方案1】:

由于您无法触摸progress,您可以将迭代器包装在另一个迭代器中,该迭代器在使用时设置一个标志,然后在未设置标志时在while循环中调用progress。同样可以通过引发异常来实现,尽管这可能会干扰进度功能。

理想情况下,您可以编辑 progress 方法,使其返回可用于检测何时完成的内容

from itertools import islice

foo = iter([1,2,3,4,5])

def progress(xs):
    list(islice(xs, 1))

finished = False

def wrapper(xs):
    for x in xs:
        yield x
    global finished
    finished = True

bar = wrapper(foo)

while not finished:
    progress(bar)

【讨论】:

  • 我认为这是问题中新约束的最佳解决方案(不能更改 progress() 实现,也没有 StopIteration 提出)。这当然也可以是自定义迭代器类,而不是生成器函数和全局变量。但只是因为我讨厌全局变量:)
【解决方案2】:

您在寻找以下语法吗?

for item in itemlist:
    do_something(item)

【讨论】:

  • 不,我不能在迭代器 (AFAICT) 上使用for 循环,因为我希望progress 一次消耗foo
  • 那你在找这个吗? stackoverflow.com/a/312464/2856376
  • 也没有,但谢谢。我已经获得了一个 progress 函数,它每次都将迭代器推进 任意 数量。
【解决方案3】:

没有通用的方法可以提前知道一个 interator 是否已经用尽。你基本上必须在上面调用next(),看看它是否能给你一个新的价值。

while True:
    progress(foo)
except StopIteration:
    pass

这是你想要的吗?

编辑:这是一个最小的 REPL 示例,说明它是如何工作的:

>>> it = iter([1,2,3,4,5])
>>> while True:
...   next(it)
...
1
2
3
4
5
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
StopIteration

所以当函数progress()尝试从foo获取下一个值时,会引发异常StopIteration

【讨论】:

  • 啊,所以这不太行,因为progress 不会在foo 用尽时提升StopIteration
  • 为了使其干净且正确分层,我将更改progress(),以便如果它有带有islice 的元素,它返回True,如果它有一个空列表False,则返回@987654334 @。或者返回它处理的元素数量。然后你可以做while progress(foo): pass
猜你喜欢
  • 2019-10-17
  • 2014-03-04
  • 2015-12-04
  • 2019-09-21
  • 1970-01-01
  • 2018-05-12
  • 1970-01-01
  • 2022-12-13
  • 2020-11-07
相关资源
最近更新 更多