使用`for i in generator`和`next(generator)`来耗尽生成器之间的区别是什么?

huangapple go评论72阅读模式
英文:

What is the difference between exhausting a generator using "for i in generator" and next(generator)

问题

我想学习如何使用生成器的返回值(但这不是我现在关心的问题)。

经过搜索,他们说当生成器耗尽时,可以从StopIteration中获取返回值,所以我用以下代码进行了测试:

def my_generator():
    yield 1
    yield 2
    yield 3
    return "done"

def exhaust_generator(_gen):
    print("===============================================")
    print("exhaust_generator")
    try:
        while True:
            print(next(_gen))
    except StopIteration as e:
        print(f"Return value: '{e.value}'")

def exhaust_generator_iter(_gen):
    print("===============================================")
    print("exhaust_generator_iter")
    try:
        for i in _gen:
            print(i)
        print(next(_gen))
    except StopIteration as e:
        print(f"Return value: {e.value}")

gen = my_generator()
gen2 = my_generator()
exhaust_generator(gen)
exhaust_generator_iter(gen2)

如您所见,两种耗尽生成器的版本之间的返回值不同,我想知道为什么。

搜索过Google,但没有找到有用的信息。

英文:

I want to learn how to use the return value of a generator (but this not what I'm concerned with now).

After searching, they said that I can get the return value from StopIteration when the generator is exhausted, so I tested it with the following code:

def my_generator():
    yield 1
    yield 2
    yield 3
    return "done"


def exhaust_generator(_gen):
    print("===============================================\n")
    print("exhaust_generator")
    try:
        while True:
            print(next(_gen))
    except StopIteration as e:
        print(f"Return value: '{e.value}'")


def exhaust_generator_iter(_gen):
    print("===============================================\n")
    print("exhaust_generator_iter")
    try:
        for i in _gen:
            print(i)
        print(next(_gen))
    except StopIteration as e:
        print(f"Return value: {e.value}")


gen = my_generator()
gen2 = my_generator()
exhaust_generator(gen)
exhaust_generator_iter(gen2)

===============================================

exhaust_generator
1
2
3
Return value: 'done'
===============================================

exhaust_generator_iter
1
2
3
Return value: None

As you can see, the return value is different between the two versions of exhausting the generator and I wonder why.

Searched google but it has not been helpful.

答案1

得分: 5

在你的第一个示例中,使用while时,你捕获了生成器在最初耗尽时引发的第一个StopIteration异常。

在你的第二个示例中,使用for时,你捕获了一个后续的 StopIteration异常,这是因为在生成器已经被for循环用尽并捕获了初始异常后,你调用next()第二次时引发的。

英文:

In your first example with the while, you're catching the first StopIteration exception raised by the generator when it's initially exhausted.

In your second example with the for, you're catching a subsequent StopIteration exception raised by calling next() a second time after the generator has already been exhausted (by the for, which caught that initial exception).

答案2

得分: 2

根据我理解,for 循环内部也会调用 next() 并最终捕获 StopIteration,以便知道何时停止调用 next()

exhaust_generator_iter 中,您的 next() 调用然后引发 第二个 StopIteration 但不带传递值。

此Stack Overflow问题 及其答案探讨了从生成器接收 return 值的方法,包括使用实用程序类或依赖注入。

英文:

As far as I understand, the for loop internally also calls next() and eventually catches the StopIteration, so it knows when to stop calling next().

Your next() call in exhaust_generator_iter then raises a second StopIteration but without the passed value.

This SO question and its answers explore ways to receive the return value from a generator, i.a. using a utility class or dependency injection.

huangapple
  • 本文由 发表于 2023年3月31日 03:19:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75892172.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定