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

时间:2011-01-19 21:55:29

标签: python iterator generator python-2.x

我有一个类似于以下的生成器函数:

def myfunct():
  ...
  yield result

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

for r in myfunct():
  dostuff(r)

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

while True:
  ...
  if something:
      my_element = pick_just_one_element(myfunct())
      dostuff(my_element)
  ...

8 个答案:

答案 0 :(得分:243)

使用

创建生成器
g = myfunct()

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

next(g)

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

如果生成器退出,它将引发StopIteration。您可以在必要时捕获此异常,也可以使用default参数next()

next(g, default_value)

答案 1 :(得分:26)

要仅选择生成器中的一个元素,请在break语句中使用for,或list(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

关于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 :(得分:2)

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

答案 3 :(得分:0)

generator = myfunct()
while True:
   my_element = generator.next()

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

答案 4 :(得分:0)

Generator是一个产生迭代器的函数。因此,一旦有了迭代器实例,就可以使用next()从迭代器中获取下一项。 例如,使用next()函数获取第一个项目,然后使用for in处理其余项目:

# create new instance of iterator by calling a generator function
items = generator_function()

# fetch and print first item
first = next(item)
print('first item:', first)

# process remaining items:
for item in items:
    print('next item:', item)

答案 5 :(得分:0)

对于那些浏览这些答案的人来说,它们是Python3的完整工作示例...在这里,您可以继续:

def numgen():
    x = 1000
    while True:
        x += 1
        yield x

nums = numgen() # because it must be the _same_ generator

for n in range(3):
    numnext = next(nums)
    print(numnext)

这将输出:

1001
1002
1003

答案 6 :(得分:0)

您可以使用解构来选择特定项目,例如:

>>> [first, *middle, last] = range(10)
>>> first
0
>>> middle
[1, 2, 3, 4, 5, 6, 7, 8]
>>> last
9

请注意,这将消耗您的生成器,因此尽管可读性强,但效率不如next()之类,并且在无限生成器上是毁灭性的:

>>> [first, *rest] = itertools.count()
???

答案 7 :(得分:-1)

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

l = list(myfunct())
l[4]