如何从生成器中仅选取一项?

问题描述 投票:0回答:9

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

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
9个回答
460
投票

使用

创建生成器
g = myfunct()

每次您想要某件物品时,请使用

next(g)

(或 Python 2.5 或更低版本中的

g.next()
)。

如果生成器退出,它将升高

StopIteration
。如果需要,您可以捕获此异常,或者使用
default
参数来
next()
:

next(g, default_value)

35
投票

要仅选取生成器的一个元素,请在

break
语句中使用
for
,或
list(itertools.islice(gen, 1))

根据您的示例(字面意思),您可以执行以下操作:

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
的唯一选择 - 是有限的,并且通常会导致奇怪的非 Python 逻辑/可读性。

底线:使用 next() 应该很少 - 就像使用

operator
模块的函数一样。使用
for x in iterator
islice
list(iterator)
和其他无缝接受迭代器的函数是在应用程序级别使用迭代器的自然方式 - 并且总是可行的。
next()
是低级的,一个额外的概念,不明显 - 正如该线程的问题所示。虽然例如在
break
中使用
for
是传统做法。


19
投票

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(items)
print('first item:', first)

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

9
投票

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

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

请注意,这会消耗您的生成器,因此虽然可读性很高,但它的效率低于

next()
之类的东西,并且对无限生成器来说是毁灭性的:

>>> first, *rest = itertools.count()
🔥🔥🔥

3
投票

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


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

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


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

0
投票

这是从迭代器获取单个对象的简短示例。如果您知道您要查找的对象的属性,它将给您。

obj = next((obj for obj in iterator if obj.prop == match_prop), None)
if obj is not None:
    pass

-4
投票

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

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