如何从生成器中选择一个项目?

我有一个像下面这样的生成器函数:

def myfunct():
...
yield result

通常调用这个函数的方法是:

for r in myfunct():
dostuff(r)
我的问题是,是否有一种方法可以在我喜欢的时候从生成器中只获得一个元素? 例如,我想这样做:

while True:
...
if something:
my_element = pick_just_one_element(myfunct())
dostuff(my_element)
...
225075 次浏览

使用以下命令创建生成器

g = myfunct()

每次你想要一样东西的时候,就去用

next(g)

(或Python 2.5或以下版本中的g.next())。

如果生成器退出,它将引发StopIteration。你可以在必要时捕获这个异常,或者使用default参数来next():

next(g, default_value)

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

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

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

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

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

如果只选择生成器中的一个元素,可以在for语句中使用breaklist(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异常处理或额外的默认值比较。

for语句节的else:只在你想在end- generator的情况下做一些特殊的事情时才需要。

关于next() / .next()的注意事项:

在Python3中,.next()方法被重命名为.__next__()有很好的理由:它被认为是低级的(PEP 3114)。在Python 2.6之前,内置函数next()并不存在。甚至还讨论过将next()移动到operator模块(这是明智的),因为它很少需要内置名称,并且有问题。

在没有默认值的情况下使用next()仍然是非常低级的实践——在正常的应用程序代码中公开抛出神秘的StopIteration,就像一个晴天霹雳。并且使用带有默认哨兵的next() -最好是直接在builtins中使用next()的唯一选项-是有限的,并且经常导致奇怪的非python逻辑/可读性。

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

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)

对于那些浏览这些答案以获得完整的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

你可以使用解构选择特定的项,例如:

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

注意,这将消耗你的生成器,所以虽然可读性很高,但它的效率低于next(),并且对无限生成器是毁灭性的:

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