Skip to content

Commit 1f7ce62

Browse files
committed
Implement PEP 380 - 'yield from' (closes #11682)
1 parent e51757f commit 1f7ce62

33 files changed

+801
-350
lines changed

Doc/library/dis.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,13 @@ the stack so that it is available for further iterations of the loop.
431431
Pops ``TOS`` and yields it from a :term:`generator`.
432432

433433

434+
.. opcode:: YIELD_FROM
435+
436+
Pops ``TOS`` and delegates to it as a subiterator from a :term:`generator`.
437+
438+
.. versionadded:: 3.3
439+
440+
434441
.. opcode:: IMPORT_STAR
435442

436443
Loads all symbols not starting with ``'_'`` directly from the module TOS to the

Doc/library/exceptions.rst

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,16 @@ The following exceptions are the exceptions that are usually raised.
250250
.. exception:: StopIteration
251251

252252
Raised by built-in function :func:`next` and an :term:`iterator`\'s
253-
:meth:`__next__` method to signal that there are no further values.
253+
:meth:`__next__` method to signal that there are no further items to be
254+
produced by the iterator.
255+
256+
The exception object has a single attribute :attr:`value`, which is
257+
given as an argument when constructing the exception, and defaults
258+
to :const:`None`.
259+
260+
When a generator function returns, a new :exc:`StopIteration` instance is
261+
raised, and the value returned by the function is used as the
262+
:attr:`value` parameter to the constructor of the exception.
254263

255264

256265
.. exception:: SyntaxError

Doc/reference/expressions.rst

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ Yield expressions
318318

319319
.. productionlist::
320320
yield_atom: "(" `yield_expression` ")"
321-
yield_expression: "yield" [`expression_list`]
321+
yield_expression: "yield" [`expression_list` | "from" `expression`]
322322

323323
The :keyword:`yield` expression is only used when defining a generator function,
324324
and can only be used in the body of a function definition. Using a
@@ -336,7 +336,10 @@ the internal evaluation stack. When the execution is resumed by calling one of
336336
the generator's methods, the function can proceed exactly as if the
337337
:keyword:`yield` expression was just another external call. The value of the
338338
:keyword:`yield` expression after resuming depends on the method which resumed
339-
the execution.
339+
the execution. If :meth:`__next__` is used (typically via either a
340+
:keyword:`for` or the :func:`next` builtin) then the result is :const:`None`,
341+
otherwise, if :meth:`send` is used, then the result will be the value passed
342+
in to that method.
340343

341344
.. index:: single: coroutine
342345

@@ -346,12 +349,29 @@ suspended. The only difference is that a generator function cannot control
346349
where should the execution continue after it yields; the control is always
347350
transferred to the generator's caller.
348351

349-
The :keyword:`yield` statement is allowed in the :keyword:`try` clause of a
352+
:keyword:`yield` expressions are allowed in the :keyword:`try` clause of a
350353
:keyword:`try` ... :keyword:`finally` construct. If the generator is not
351354
resumed before it is finalized (by reaching a zero reference count or by being
352355
garbage collected), the generator-iterator's :meth:`close` method will be
353356
called, allowing any pending :keyword:`finally` clauses to execute.
354357

358+
When ``yield from expression`` is used, it treats the supplied expression as
359+
a subiterator. All values produced by that subiterator are passed directly
360+
to the caller of the current generator's methods. Any values passed in with
361+
:meth:`send` and any exceptions passed in with :meth:`throw` are passed to
362+
the underlying iterator if it has the appropriate methods. If this is not the
363+
case, then :meth:`send` will raise :exc:`AttributeError` or :exc:`TypeError`,
364+
while :meth:`throw` will just raise the passed in exception immediately.
365+
366+
When the underlying iterator is complete, the :attr:`~StopIteration.value`
367+
attribute of the raised :exc:`StopIteration` instance becomes the value of
368+
the yield expression. It can be either set explicitly when raising
369+
:exc:`StopIteration`, or automatically when the sub-iterator is a generator
370+
(by returning a value from the sub-generator).
371+
372+
The parentheses can be omitted when the :keyword:`yield` expression is the
373+
sole expression on the right hand side of an assignment statement.
374+
355375
.. index:: object: generator
356376

357377
The following generator's methods can be used to control the execution of a
@@ -444,6 +464,10 @@ generator functions::
444464
The proposal to enhance the API and syntax of generators, making them
445465
usable as simple coroutines.
446466

467+
:pep:`0380` - Syntax for Delegating to a Subgenerator
468+
The proposal to introduce the :token:`yield_from` syntax, making delegation
469+
to sub-generators easy.
470+
447471

448472
.. _primaries:
449473

Doc/reference/simple_stmts.rst

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -425,10 +425,10 @@ When :keyword:`return` passes control out of a :keyword:`try` statement with a
425425
:keyword:`finally` clause, that :keyword:`finally` clause is executed before
426426
really leaving the function.
427427

428-
In a generator function, the :keyword:`return` statement is not allowed to
429-
include an :token:`expression_list`. In that context, a bare :keyword:`return`
430-
indicates that the generator is done and will cause :exc:`StopIteration` to be
431-
raised.
428+
In a generator function, the :keyword:`return` statement indicates that the
429+
generator is done and will cause :exc:`StopIteration` to be raised. The returned
430+
value (if any) is used as an argument to construct :exc:`StopIteration` and
431+
becomes the :attr:`StopIteration.value` attribute.
432432

433433

434434
.. _yield:
@@ -450,6 +450,7 @@ The :keyword:`yield` statement is only used when defining a generator function,
450450
and is only used in the body of the generator function. Using a :keyword:`yield`
451451
statement in a function definition is sufficient to cause that definition to
452452
create a generator function instead of a normal function.
453+
453454
When a generator function is called, it returns an iterator known as a generator
454455
iterator, or more commonly, a generator. The body of the generator function is
455456
executed by calling the :func:`next` function on the generator repeatedly until
@@ -469,14 +470,25 @@ resumed before it is finalized (by reaching a zero reference count or by being
469470
garbage collected), the generator-iterator's :meth:`close` method will be
470471
called, allowing any pending :keyword:`finally` clauses to execute.
471472

473+
When ``yield from expression`` is used, it treats the supplied expression as
474+
a subiterator, producing values from it until the underlying iterator is
475+
exhausted.
476+
477+
For full details of :keyword:`yield` semantics, refer to the :ref:`yieldexpr`
478+
section.
479+
472480
.. seealso::
473481

474482
:pep:`0255` - Simple Generators
475483
The proposal for adding generators and the :keyword:`yield` statement to Python.
476484

477485
:pep:`0342` - Coroutines via Enhanced Generators
478-
The proposal that, among other generator enhancements, proposed allowing
479-
:keyword:`yield` to appear inside a :keyword:`try` ... :keyword:`finally` block.
486+
The proposal to enhance the API and syntax of generators, making them
487+
usable as simple coroutines.
488+
489+
:pep:`0380` - Syntax for Delegating to a Subgenerator
490+
The proposal to introduce the :token:`yield_from` syntax, making delegation
491+
to sub-generators easy.
480492

481493

482494
.. _raise:

Doc/whatsnew/3.3.rst

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,22 @@ inspection of exception attributes::
195195
print("You are not allowed to read document.txt")
196196

197197

198+
PEP 380: Syntax for Delegating to a Subgenerator
199+
================================================
200+
201+
PEP 380 adds the ``yield from`` expression, allowing a generator to delegate
202+
part of its operations to another generator. This allows a section of code
203+
containing 'yield' to be factored out and placed in another generator.
204+
Additionally, the subgenerator is allowed to return with a value, and the
205+
value is made available to the delegating generator.
206+
While designed primarily for use in delegating to a subgenerator, the ``yield
207+
from`` expression actually allows delegation to arbitrary subiterators.
208+
209+
(Implementation by Greg Ewing, integrated into 3.3 by Renaud Blanch, Ryan
210+
Kelly and Nick Coghlan, documentation by Zbigniew Jędrzejewski-Szmek and
211+
Nick Coghlan)
212+
213+
198214
PEP 3155: Qualified name for classes and functions
199215
==================================================
200216

@@ -208,7 +224,6 @@ it provides better information about where they were actually defined, and
208224
how they might be accessible from the global scope.
209225

210226
Example with (non-bound) methods::
211-
212227
>>> class C:
213228
... def meth(self):
214229
... pass

Grammar/Grammar

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,13 @@ arglist: (argument ',')* (argument [',']
121121
|'**' test)
122122
# The reason that keywords are test nodes instead of NAME is that using NAME
123123
# results in an ambiguity. ast.c makes sure it's a NAME.
124-
argument: test [comp_for] | test '=' test # Really [keyword '='] test
124+
argument: (test) [comp_for] | test '=' test # Really [keyword '='] test
125125
comp_iter: comp_for | comp_if
126126
comp_for: 'for' exprlist 'in' or_test [comp_iter]
127127
comp_if: 'if' test_nocond [comp_iter]
128128

129129
# not used in grammar, but may appear in "node" passed from Parser to Compiler
130130
encoding_decl: NAME
131131

132-
yield_expr: 'yield' [testlist]
132+
yield_expr: 'yield' [yield_arg]
133+
yield_arg: 'from' test | testlist

Include/Python-ast.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ struct _expr {
245245
} GeneratorExp;
246246

247247
struct {
248+
int is_from;
248249
expr_ty value;
249250
} Yield;
250251

@@ -487,8 +488,9 @@ expr_ty _Py_DictComp(expr_ty key, expr_ty value, asdl_seq * generators, int
487488
#define GeneratorExp(a0, a1, a2, a3, a4) _Py_GeneratorExp(a0, a1, a2, a3, a4)
488489
expr_ty _Py_GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int
489490
col_offset, PyArena *arena);
490-
#define Yield(a0, a1, a2, a3) _Py_Yield(a0, a1, a2, a3)
491-
expr_ty _Py_Yield(expr_ty value, int lineno, int col_offset, PyArena *arena);
491+
#define Yield(a0, a1, a2, a3, a4) _Py_Yield(a0, a1, a2, a3, a4)
492+
expr_ty _Py_Yield(int is_from, expr_ty value, int lineno, int col_offset,
493+
PyArena *arena);
492494
#define Compare(a0, a1, a2, a3, a4, a5) _Py_Compare(a0, a1, a2, a3, a4, a5)
493495
expr_ty _Py_Compare(expr_ty left, asdl_int_seq * ops, asdl_seq * comparators,
494496
int lineno, int col_offset, PyArena *arena);

Include/frameobject.h

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,46 @@ extern "C" {
99
#endif
1010

1111
typedef struct {
12-
int b_type; /* what kind of block this is */
13-
int b_handler; /* where to jump to find handler */
14-
int b_level; /* value stack level to pop to */
12+
int b_type; /* what kind of block this is */
13+
int b_handler; /* where to jump to find handler */
14+
int b_level; /* value stack level to pop to */
1515
} PyTryBlock;
1616

1717
typedef struct _frame {
1818
PyObject_VAR_HEAD
19-
struct _frame *f_back; /* previous frame, or NULL */
20-
PyCodeObject *f_code; /* code segment */
21-
PyObject *f_builtins; /* builtin symbol table (PyDictObject) */
22-
PyObject *f_globals; /* global symbol table (PyDictObject) */
23-
PyObject *f_locals; /* local symbol table (any mapping) */
24-
PyObject **f_valuestack; /* points after the last local */
19+
struct _frame *f_back; /* previous frame, or NULL */
20+
PyCodeObject *f_code; /* code segment */
21+
PyObject *f_builtins; /* builtin symbol table (PyDictObject) */
22+
PyObject *f_globals; /* global symbol table (PyDictObject) */
23+
PyObject *f_locals; /* local symbol table (any mapping) */
24+
PyObject **f_valuestack; /* points after the last local */
2525
/* Next free slot in f_valuestack. Frame creation sets to f_valuestack.
2626
Frame evaluation usually NULLs it, but a frame that yields sets it
2727
to the current stack top. */
2828
PyObject **f_stacktop;
29-
PyObject *f_trace; /* Trace function */
30-
31-
/* In a generator, we need to be able to swap between the exception
32-
state inside the generator and the exception state of the calling
33-
frame (which shouldn't be impacted when the generator "yields"
34-
from an except handler).
35-
These three fields exist exactly for that, and are unused for
36-
non-generator frames. See the SAVE_EXC_STATE and SWAP_EXC_STATE
37-
macros in ceval.c for details of their use. */
29+
PyObject *f_trace; /* Trace function */
30+
PyObject *f_yieldfrom; /* Iterator being delegated to by yield from */
31+
32+
/* In a generator, we need to be able to swap between the exception
33+
state inside the generator and the exception state of the calling
34+
frame (which shouldn't be impacted when the generator "yields"
35+
from an except handler).
36+
These three fields exist exactly for that, and are unused for
37+
non-generator frames. See the SAVE_EXC_STATE and SWAP_EXC_STATE
38+
macros in ceval.c for details of their use. */
3839
PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
3940

4041
PyThreadState *f_tstate;
41-
int f_lasti; /* Last instruction if called */
42+
int f_lasti; /* Last instruction if called */
4243
/* Call PyFrame_GetLineNumber() instead of reading this field
4344
directly. As of 2.3 f_lineno is only valid when tracing is
4445
active (i.e. when f_trace is set). At other times we use
4546
PyCode_Addr2Line to calculate the line from the current
4647
bytecode index. */
47-
int f_lineno; /* Current line number */
48-
int f_iblock; /* index in f_blockstack */
48+
int f_lineno; /* Current line number */
49+
int f_iblock; /* index in f_blockstack */
4950
PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
50-
PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
51+
PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
5152
} PyFrameObject;
5253

5354

Include/genobject.h

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ extern "C" {
1111
struct _frame; /* Avoid including frameobject.h */
1212

1313
typedef struct {
14-
PyObject_HEAD
15-
/* The gi_ prefix is intended to remind of generator-iterator. */
14+
PyObject_HEAD
15+
/* The gi_ prefix is intended to remind of generator-iterator. */
1616

17-
/* Note: gi_frame can be NULL if the generator is "finished" */
18-
struct _frame *gi_frame;
17+
/* Note: gi_frame can be NULL if the generator is "finished" */
18+
struct _frame *gi_frame;
1919

20-
/* True if generator is being executed. */
21-
int gi_running;
20+
/* True if generator is being executed. */
21+
int gi_running;
2222

23-
/* The code object backing the generator */
24-
PyObject *gi_code;
23+
/* The code object backing the generator */
24+
PyObject *gi_code;
2525

26-
/* List of weak reference. */
27-
PyObject *gi_weakreflist;
26+
/* List of weak reference. */
27+
PyObject *gi_weakreflist;
2828
} PyGenObject;
2929

3030
PyAPI_DATA(PyTypeObject) PyGen_Type;
@@ -34,6 +34,7 @@ PyAPI_DATA(PyTypeObject) PyGen_Type;
3434

3535
PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *);
3636
PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *);
37+
PyAPI_FUNC(int) PyGen_FetchStopIterationValue(PyObject **);
3738

3839
#ifdef __cplusplus
3940
}

Include/graminit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,4 @@
8181
#define comp_if 334
8282
#define encoding_decl 335
8383
#define yield_expr 336
84+
#define yield_arg 337

0 commit comments

Comments
 (0)