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

发布于 2024-10-12 20:52:47 字数 359 浏览 12 评论 0原文

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

def myfunct():
  ...
  yield result

调用该函数的通常方法是:

for r in myfunct():
  dostuff(r)

我的问题是,有没有一种方法可以随时从生成器中获取一个元素? 例如,我想做类似的事情:

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

I have a generator function like the following:

def myfunct():
  ...
  yield result

The usual way to call this function would be:

for r in myfunct():
  dostuff(r)

My question, is there a way to get just one element from the generator whenever I like?
For example, I'd like to do something like:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

戴着白色围巾的女孩 2024-10-19 20:52:47

(或在 Python 2.5 或更低版本中使用 g.next())创建生成器

g = myfunct()

使用每次您想要一个项目时,使用

next(g)

如果生成器退出,它将引发 StopIteration。如果需要,您可以捕获此异常,或者使用 next()default 参数:

next(g, default_value)

Create a generator using

g = myfunct()

Everytime you would like an item, use

next(g)

(or g.next() in Python 2.5 or below).

If the generator exits, it will raise StopIteration. You can either catch this exception if necessary, or use the default argument to next():

next(g, default_value)
﹎☆浅夏丿初晴 2024-10-19 20:52:47

要仅选取生成器的一个元素,请在 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:

关于 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 是常规做法。

For picking just one element of a generator use break in a for statement, or list(itertools.islice(gen, 1))

According to your example (literally) you can do something like:

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

If you want "get just one element from the [once generated] generator whenever I like" (I suppose 50% thats the original intention, and the most common intention) then:

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

This way explicit use of generator.next() can be avoided, and end-of-input handling doesn't require (cryptic) StopIteration exception handling or extra default value comparisons.

The else: of for statement section is only needed if you want do something special in case of end-of-generator.

Note on next() / .next():

In Python3 the .next() method was renamed to .__next__() for good reason: its considered low-level (PEP 3114). Before Python 2.6 the builtin function next() did not exist. And it was even discussed to move next() to the operator module (which would have been wise), because of its rare need and questionable inflation of builtin names.

Using next() without default is still very low-level practice - throwing the cryptic StopIteration like a bolt out of the blue in normal application code openly. And using next() with default sentinel - which best should be the only option for a next() directly in builtins - is limited and often gives reason to odd non-pythonic logic/readablity.

Bottom line: Using next() should be very rare - like using functions of operator module. Using for x in iterator , islice, list(iterator) and other functions accepting an iterator seamlessly is the natural way of using iterators on application level - and quite always possible. next() is low-level, an extra concept, unobvious - as the question of this thread shows. While e.g. using break in for is conventional.

债姬 2024-10-19 20:52:47

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)

Generator is a function that produces an iterator. Therefore, once you have iterator instance, use next() to fetch the next item from the iterator.
As an example, use next() function to fetch the first item, and later use for in to process remaining items:

# 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)
随风而去 2024-10-19 20:52:47

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

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

请注意,这将消耗您的生成器,因此虽然可读性很高,但它的效率低于 next() 之类的东西,并且对无限生成器来说是毁灭性的:

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

You can pick specific items using destructuring, e.g.:

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

Note that this is going to consume your generator, so while highly readable, it is less efficient than something like next(), and ruinous on infinite generators:

>>> first, *rest = itertools.count()
????????????
左耳近心 2024-10-19 20:52:47

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

I don't believe there's a convenient way to retrieve an arbitrary value from a generator. The generator will provide a next() method to traverse itself, but the full sequence is not produced immediately to save memory. That's the functional difference between a generator and a list.

还在原地等你 2024-10-19 20:52:47
generator = myfunct()
while True:
   my_element = generator.next()

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

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

make sure to catch the exception thrown after the last element is taken

云归处 2024-10-19 20:52:47

对于那些浏览这些答案以获取 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

For those of you scanning through these answers for a complete working example for Python3... well here ya go:

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)

This outputs:

1001
1002
1003
病女 2024-10-19 20:52:47

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

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

This is a short example of getting a single object from an iterator. If you know the attribute, or property of the object your looking for this will give it to you.

obj = next((obj for obj in iterator() if obj.prop == match_prop), None)
if obj is not None:
    pass
多彩岁月 2024-10-19 20:52:47

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

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

I believe the only way is to get a list from the iterator then get the element you want from that list.

l = list(myfunct())
l[4]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文