This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Using for...in.. generator-iterator
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: steven.daprano, xtreak, yoonghm
Priority: normal Keywords:

Created on 2019-01-12 04:26 by yoonghm, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (3)
msg333510 - (view) Author: Yoong Hor Meng (yoonghm) Date: 2019-01-12 04:26
def f():
    print('-- Start --')
    yield 1
    print('-- Middle --')
    yield 2
    print('-- Finished --')
    yield 3

gen = f()
for x in gen:
    print('Another things ...')
    next(gen)


The output:

-- Start --
Another things ...
-- Middle --
-- Finished --
Another things ...

I noticed that the generator function will execute whenever it is in the for...in loop.  Is it expected? I do not see it documented anywhere. Thanks.
msg333515 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2019-01-12 06:28
This is not a bug, it is standard behaviour for all iterators, not just generators.

For loops work by calling next() on the iterator object, if you call next() on the same object inside the loop, that has the effect of advancing the for loop.

You say:

> I noticed that the generator function will execute whenever it is in the for...in loop.

but that's actually incorrect, as the generator FUNCTION f() is not inside the for loop. Each time you call the generator function f() you get a separate, independent generator object. In this case, you only call f() once, so you only have one generator object `gen`. Each time next(gen) is called, it advances to the next yield. It doesn't matter whether you call it manually, or the interpreter calls it for you using the for loop.

Try these two examples and compare their difference:

gen = f()
for x in gen:
    print(x, "outer loop")
    for y in gen:
        print(y, "inner loop")


versus:

for x in f():
    print(x, "outer loop")
    for y in f():
        print(y, "inner loop")
msg333517 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2019-01-12 06:33
I was also typing a similar reply and Steve explained it better :) Just to add there is a note on implicit next call on a for loop in the documentation.

https://docs.python.org/3/reference/expressions.html#generator.__next__

> Starts the execution of a generator function or resumes it at the last executed yield expression. When a generator function is resumed with a __next__() method, the current yield expression always evaluates to None. The execution then continues to the next yield expression, where the generator is suspended again, and the value of the expression_list is returned to __next__()’s caller. If the generator exits without yielding another value, a StopIteration exception is raised.

> This method is normally called implicitly, e.g. by a for loop, or by the built-in next() function.
History
Date User Action Args
2022-04-11 14:59:10adminsetgithub: 79906
2019-01-12 06:33:22xtreaksetnosy: + xtreak
messages: + msg333517
2019-01-12 06:28:27steven.dapranosetstatus: open -> closed

nosy: + steven.daprano
messages: + msg333515

resolution: not a bug
stage: resolved
2019-01-12 04:26:24yoonghmcreate