Skip to content

Commit 9450013

Browse files
committed
apply suggestions from code review
1 parent 628a3a4 commit 9450013

File tree

1 file changed

+19
-14
lines changed

1 file changed

+19
-14
lines changed

InternalDocs/generators.md

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ Generators and Coroutines
55
Generators
66
----------
77

8-
The implementation of generators in CPython consists of instances of `PyGenObject`
9-
and bytecode instructions that operate on instances of this type.
10-
11-
A generator object is invoked in a [`frame`](frames.md), like a function.
12-
The difference is that a function returns to the calling frame only once,
13-
while a generator "returns" to the caller every time it emits a new item
14-
with a
8+
Generators in CPython are implemented with the struct `PyGenObject`.
9+
They consist of a [`frame`](frames.md) and metadata about the generator's
10+
execution state.
11+
12+
A generator object resumes execution in its frame when its `send()`
13+
method is called. This is analogous to a function executing in its own
14+
fram when it is called, but a function returns to the calling frame only once,
15+
while a generator "returns" execution to the caller's frame every time
16+
it emits a new item with a
1517
[`yield` expression](https://docs.python.org/dev/reference/expressions.html#yield-expressions).
1618
This is implemented by the
1719
[`YIELD_VALUE`](https://docs.python.org/dev/library/dis.html#opcode-YIELD_VALUE)
@@ -38,16 +40,17 @@ Generator Object Creation and Destruction
3840

3941
The bytecode of a generator function begins with a
4042
[`RETURN_GENERATOR`](https://docs.python.org/dev/library/dis.html#opcode-RETURN_GENERATOR)
41-
instruction, which creates a generator object, along with its embedded frame.
43+
instruction, which creates a generator object, including its embedded frame.
4244
The generator's frame is initialized as a copy of the frame in which
4345
`RETURN_GENERATOR` is executing, but its `owner` field is overwritten to indicate
4446
that it is owned by a generator. Finally, `RETURN_GENERATOR` pushes the new generator
45-
object to the stack and returns to the caller of the generator function. When the
46-
generator is next resumed by [`gen_send_ex2()`](../Objects/genobject.c),
47-
`_PyEval_EvalFrame()` is called to continue executing the generator function,
48-
in the frame that is embedded in the generator object.
47+
object to the stack and returns to the caller of the generator function (at
48+
which time its frame is destroyed). When the generator is next resumed by
49+
[`gen_send_ex2()`](../Objects/genobject.c), `_PyEval_EvalFrame()` is called
50+
to continue executing the generator function, in the frame that is embedded in
51+
the generator object.
4952

50-
When a generator object is destructed in [`gen_dealloc`](../Objects/genobject.c),
53+
When a generator object is destroyed in [`gen_dealloc`](../Objects/genobject.c),
5154
its embedded `_PyInterpreterFrame` field may need to be preserved, if it is exposed
5255
to Python as part of a [`PyFrameObject`](frames.md#frame-objects). This is detected
5356
in [`_PyFrame_ClearExceptCode`](../Python/frame.c) by the fact that the interpreter
@@ -63,7 +66,9 @@ The [`FOR_ITER`](https://docs.python.org/dev/library/dis.html#opcode-FOR_ITER)
6366
instruction calls `__next__` on the iterator which is on the top of the stack,
6467
and pushes the result to the stack. It has [`specializations`](adaptive.md)
6568
for a few common iterator types, including `FOR_ITER_GEN`, for iterating over
66-
a generator.
69+
a generator. `FOR_ITER_GEN` bypasses the call to `__next__`, and instead
70+
directly pushes the generator stack and resumes its execution from the
71+
instruction that follows the last yield.
6772

6873
Chained Generators
6974
------------------

0 commit comments

Comments
 (0)