Skip to content

Commit 6170e3c

Browse files
committed
Doc: Clarify async generator expression behavior with nested async comprehensions
1 parent 2721f8a commit 6170e3c

File tree

2 files changed

+28
-10
lines changed

2 files changed

+28
-10
lines changed

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,16 @@ CLAUDE.local.md
178178
#### main branch only stuff below this line, things to backport go above. ####
179179
# main branch only: ABI files are not checked/maintained.
180180
Doc/data/python*.abi
181+
validation_test.py
182+
test_nested_difference.py
183+
commit_message.txt
184+
demo_issue_138097.py
185+
PR_template.md
186+
check_format.py
187+
lint_check.py
188+
Doc/reference/expressions.rst
189+
check_our_changes.py
190+
clean_whitespace.py
191+
detailed_check.py
192+
check_fixed.py
193+
final_lint_check.py

Doc/reference/expressions.rst

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -310,10 +310,10 @@ the iterable expression in the leftmost :keyword:`!for` clause, it is called an
310310
execution of the coroutine function in which it appears.
311311
See also :pep:`530`.
312312

313-
Note that this behavior extends to nested comprehensions: if a comprehension
314-
contains an asynchronous comprehension in a nested scope, the outer comprehension
315-
implicitly becomes asynchronous. This also applies to generator expressions that
316-
contain asynchronous comprehensions.
313+
Note that this behavior extends to nested scopes: if a comprehension or generator
314+
expression contains asynchronous comprehensions (but not asynchronous generator
315+
expressions) in nested scopes, the outer comprehension or generator expression
316+
implicitly becomes asynchronous.
317317

318318
.. versionadded:: 3.6
319319
Asynchronous comprehensions were introduced.
@@ -489,16 +489,21 @@ clauses or :keyword:`await` expressions it is called an
489489
expression returns a new asynchronous generator object,
490490
which is an asynchronous iterator (see :ref:`async-iterators`).
491491

492-
Note that a generator expression becomes an asynchronous generator expression
493-
if it contains asynchronous comprehensions in nested scopes, such as an async
494-
list comprehension within the generator expression. For example::
492+
Note that a generator expression also becomes an asynchronous generator expression
493+
if it contains asynchronous comprehensions (list, set, or dict comprehensions with
494+
:keyword:`!async for`) in nested scopes. For example::
495495

496496
# This becomes an async generator expression
497497
([a async for a in async_iterable] for x in [1])
498498

499-
This behavior occurs because the inner async comprehension requires an
500-
asynchronous context to execute, which causes the entire generator expression
501-
to become asynchronous.
499+
However, a generator expression that contains an asynchronous generator expression
500+
does *not* become asynchronous itself::
501+
502+
# This remains a regular generator expression
503+
((a async for a in async_iterable) for x in [1])
504+
505+
This distinction exists because async comprehensions require immediate evaluation
506+
in an async context, while async generator expressions are lazily evaluated.
502507

503508
.. versionadded:: 3.6
504509
Asynchronous generator expressions were introduced.

0 commit comments

Comments
 (0)