如何从生成器中选择一个项目(在python中)?

问题描述 投票:164回答:5

我有一个如下的生成器函数:

def myfunct():
  ...
  yield result

调用此函数的常用方法是:

for r in myfunct():
  dostuff(r)

我的问题是,有什么方法可以随时从发电机中获取一个元素吗?例如,我想做类似的事情:

while True:
  ...
  if something:
      my_element = pick_just_one_element(myfunct())
      dostuff(my_element)
  ...
python iterator generator python-2.x
5个回答
247
投票

使用创建生成器

g = myfunct()

每次你想要一件商品,请使用

next(g)

(或Python 2.5或更低版本中的g.next())。

如果发电机退出,它将提升StopIteration。如有必要,您可以捕获此异常,或使用default参数next()

next(g, default_value)

26
投票

break语句中使用forlist(itertools.islice(gen, 1))只选择生成器中的一个元素

根据你的例子(laterally),你可以这样做:

while True:
  ...
  if something:
      for my_element in myfunct():
          dostuff(my_element)
          break
      else:
          do_generator_empty()

如果你想“在我喜欢的时候从[曾经生成的]生成器中获取一个元素”(我认为50%是初衷和最常见的意图),那么:

gen = myfunct()
while True:
  ...
  if something:
      for my_element in gen:
          dostuff(my_element)
          break
      else:
          do_generator_empty()

这样可以避免显式使用generator.next(),并且输入结束处理不需要(隐藏的)StopIteration异常处理或额外的默认值比较。

else:语句部分的for仅在你想要在发生器结束时做一些特殊事情时才需要。

Note on next() / .next():

在Python3中,.next()方法被重命名为.__next__()有充分理由:它被认为是低级别(PEP 3114)。在Python 2.6之前,内置函数next()不存在。甚至还讨论过将next()转移到operator模块(这本来是明智的),因为其内在名称的罕见需求和可疑的膨胀。

使用next()没有默认值仍然是非常低级别的练习 - 在正常的应用程序代码中公开地抛出神秘的StopIteration像一个螺栓。使用带有默认哨兵的next() - 最好应该是next()builtins的唯一选择 - 是有限的,并且经常给出奇怪的非pythonic逻辑/可读性的理由。

结论:使用next()非常罕见 - 就像使用operator模块的功能一样。使用for x in iteratorislicelist(iterator)和其他无缝接受迭代器的函数是在应用程序级别使用迭代器的自然方式 - 而且总是可行的。 next()是低级别的,一个额外的概念,不明显 - 正如这个线程的问题所示。例如,在break中使用for是常规的。


2
投票

我不相信有一种方便的方法从生成器中检索任意值。生成器将提供next()方法来遍历自身,但不会立即生成完整序列以节省内存。这是生成器和列表之间的功能差异。


0
投票
generator = myfunct()
while True:
   my_element = generator.next()

确保捕获在获取最后一个元素后抛出的异常


-1
投票

我相信唯一的方法是从迭代器中获取一个列表,然后从该列表中获取所需的元素。

l = list(myfunct())
l[4]
© www.soinside.com 2019 - 2024. All rights reserved.