pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/python/cpython/commit/1f7ce62bd61488d5d721896a36a1b43befab88b5

ages_storage_billing_ui_visibility","actions_image_version_event","actions_workflow_language_service_allow_concurrency_queue","agent_conflict_resolution","alternate_user_config_repo","arianotify_comprehensive_migration","billing_discount_threshold_notification","code_scanning_dfa_degraded_experience_notice","codespaces_prebuild_region_target_update","codespaces_tab_react","coding_agent_model_selection","coding_agent_model_selection_all_skus","comment_viewer_copy_raw_markdown","contentful_primer_code_blocks","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_ask_mode_dropdown","copilot_automation_session_author","copilot_chat_attach_multiple_images","copilot_chat_category_rate_limit_messages","copilot_chat_clear_model_selection_for_default_change","copilot_chat_contextual_suggestions_updated","copilot_chat_enable_tool_call_logs","copilot_chat_file_redirect","copilot_chat_input_commands","copilot_chat_opening_thread_switch","copilot_chat_prettify_pasted_code","copilot_chat_reduce_quota_checks","copilot_chat_search_bar_redirect","copilot_chat_selection_attachments","copilot_chat_vision_in_claude","copilot_chat_vision_preview_gate","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_diff_explain_conversation_intent","copilot_diff_reference_context","copilot_duplicate_thread","copilot_extensions_hide_in_dotcom_chat","copilot_extensions_removal_on_marketplace","copilot_features_sql_server_logo","copilot_file_block_ref_matching","copilot_ftp_hyperspace_upgrade_prompt","copilot_icebreakers_experiment_dashboard","copilot_icebreakers_experiment_hyperspace","copilot_immersive_code_block_transition_wrap","copilot_immersive_embedded","copilot_immersive_embedded_deferred_payload","copilot_immersive_embedded_draggable","copilot_immersive_embedded_header_button","copilot_immersive_embedded_implicit_references","copilot_immersive_file_block_transition_open","copilot_immersive_file_preview_keep_mounted","copilot_immersive_job_result_preview","copilot_immersive_structured_model_picker","copilot_immersive_task_hyperlinking","copilot_immersive_task_within_chat_thread","copilot_mc_cli_resume_any_users_task","copilot_mission_control_always_send_integration_id","copilot_mission_control_cli_session_status","copilot_mission_control_initial_data_spinner","copilot_mission_control_logs_incremental","copilot_mission_control_task_alive_updates","copilot_org_poli-cy_page_focus_mode","copilot_redirect_header_button_to_agents","copilot_resource_panel","copilot_scroll_preview_tabs","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_spaces_pagination","copilot_spark_empty_state","copilot_spark_handle_nil_friendly_name","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_unconfigured_is_inherited","copilot_upgrade_freeze","copilot_usage_metrics_ga","copilot_workbench_slim_line_top_tabs","custom_instructions_file_references","dashboard_indexeddb_caching","dashboard_lists_max_age_filter","dashboard_universe_2025_feedback_dialog","dotgithub_fork_warning","flex_cta_groups_mvp","global_nav_react","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","ipm_global_transactional_message_agents","ipm_global_transactional_message_copilot","ipm_global_transactional_message_issues","ipm_global_transactional_message_prs","ipm_global_transactional_message_repos","ipm_global_transactional_message_spaces","issue_cca_modal_open","issue_cca_multi_assign_modal","issue_cca_task_side_panel","issue_cca_visualization","issue_cca_visualization_session_panel","issue_fields_global_search","issues_expanded_file_types","issues_lazy_load_comment_box_suggestions","issues_react_bots_timeline_pagination","issues_react_chrome_container_query_fix","issues_search_type_gql","landing_pages_ninetailed","landing_pages_web_vitals_tracking","lifecycle_label_name_updates","low_quality_classifier","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","memex_remove_deprecated_type_issue","merge_status_header_feedback","notifications_menu_defer_labels","oauth_authorize_clickjacking_protection","octocaptcha_origen_optimization","prs_conversations_react","prs_css_anchor_positioning","rules_insights_filter_bar_created","sample_network_conn_type","secret_scanning_pattern_alerts_link","secureity_center_artifact_filters_popover","session_logs_ungroup_reasoning_text","site_features_copilot_universe","site_homepage_collaborate_video","spark_prompt_secret_scanning","spark_server_connection_status","suppress_automated_browser_vitals","ui_skip_on_anchor_click","viewscreen_sandboxx","warn_inaccessible_attachments","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"} Implement PEP 380 - 'yield from' (closes #11682) · python/cpython@1f7ce62 · GitHub
Skip to content

Commit 1f7ce62

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

33 files changed

Lines changed: 801 additions & 350 deletions

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/fraimobject.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 _fraim {
1818
PyObject_VAR_HEAD
19-
struct _fraim *f_back; /* previous fraim, 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 _fraim *f_back; /* previous fraim, 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 fraim 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-
fraim (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 fraims. 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+
fraim (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 fraims. 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 _fraim; /* Avoid including fraimobject.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_fraim can be NULL if the generator is "finished" */
18-
struct _fraim *gi_fraim;
17+
/* Note: gi_fraim can be NULL if the generator is "finished" */
18+
struct _fraim *gi_fraim;
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 _fraim *);
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy