@@ -3,11 +3,12 @@ Title: Unpacking in Comprehensions
33Author: Adam Hartz <
[email protected] >, Erik Demaine <
[email protected] >
44Sponsor: Jelle Zijlstra <jelle.zijlstra at gmail.com>
55Discussions-To: https://discuss.python.org/t/99435
6- Status: Draft
6+ Status: Accepted
77Type: Standards Track
88Created: 19-Jul-2025
99Python-Version: 3.15
1010Post-History: `
16-Oct-2021 <
https://mail.python.org/archives/list/[email protected] /thread/7G732VMDWCRMWM4PKRG6ZMUKH7SUC7SH/ >`__, `
22-Jun-2025 <
https://discuss.python.org/t/pre-pep-unpacking-in-comprehensions/96362 >`__, `
19-Jul-2025 <
https://discuss.python.org/t/pep-798-unpacking-in-comprehensions/99435 >`__
11+ Resolution: `03-Nov-2025 <https://discuss.python.org/t/pep-798-unpacking-in-comprehensions/99435/60 >`__
1112
1213
1314Abstract
@@ -109,7 +110,7 @@ number of iterables.
109110
110111This proposal represents a natural extension of the language, paralleling
111112existing syntactic structures: where ``[x, y, z] `` creates a list from a fixed
112- number of vaues , ``[item for item in items] `` creates a list from an arbitrary
113+ number of values , ``[item for item in items] `` creates a list from an arbitrary
113114number of values; this proposal extends that notion to the construction of
114115lists that involve unpacking, making ``[*item for item in items] `` analogous to
115116``[*x, *y, *z] ``.
@@ -222,19 +223,17 @@ Semantics: Generator Expressions
222223Generator expressions using the unpacking syntax should form new generators
223224producing values from the concatenation of the iterables given by the
224225expressions. Specifically, the behavior is defined to be equivalent to the
225- following::
226+ following (though without defining or referencing the looping variable `` i ``) ::
226227
227228 # equivalent to g = (*expr for x in it)
228229 def generator():
229230 for x in it:
230- yield from expr
231+ for i in expr:
232+ yield i
231233
232234 g = generator()
233235
234- Since ``yield from `` is not allowed inside of async generators (see the section
235- of :pep: `525 ` on Asynchronous ``yield from ``), the equivalent for ``(*expr
236- async for x in ait()) `` is more like the following (though of course this new
237- form should not define or reference the looping variable ``i ``)::
236+ .. code :: python
238237
239238 # equivalent to g = (*expr async for x in ait())
240239 async def generator ():
@@ -244,11 +243,8 @@ form should not define or reference the looping variable ``i``)::
244243
245244 g = generator()
246245
247- The specifics of these semantics should be revisited in the future,
248- particularly if async generators receive support for ``yield from `` (in which
249- case the async variant may wish to be changed to make use of ``yield from ``
250- instead of an explicit loop). See :ref: `pep798-alternativegenexpsemantics ` for
251- more discussion.
246+
247+ See :ref: `pep798-alternativegenexpsemantics ` for more discussion of these semantics.
252248
253249Interaction with Assignment Expressions
254250^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -267,7 +263,8 @@ form, ``y`` will be bound in the containing scope instead of locally::
267263
268264 def generator():
269265 for i in (0, 2, 4):
270- yield from (y := [i, i+1])
266+ for j in (y := [i, i+1]):
267+ yield j
271268
272269In this example, the subexpression ``(y := [i, i+1]) `` is evaluated exactly
273270three times before the generator is exhausted: just after assigning ``i `` in
@@ -402,13 +399,14 @@ particular phrasing of any of the old error messages being replaced, which we
402399expect to be rare.
403400
404401One related concern is that a hypothetical future decision to change the
405- semantics of async generator expressions to make use of ``yield from `` during
402+ semantics of generator expressions to make use of ``yield from `` during
406403unpacking (delegating to generators that are being unpacked) would not be
407404backwards-compatible because it would affect the behavior of the resulting
408- generators when used with ``.asend() ``, ``.athrow() ``, and ``.aclose() ``. That
409- said, despite being backwards-incompatible, such a change would be unlikely to
410- have a large impact because it would only affect the behavior of structures
411- that, under this proposal, are not particularly useful. See
405+ generators when used with ``.send() ``/``.asend() ``, ``.throw() ``/``.athrow() ``,
406+ and ``.close() ``/``.aclose() ``. That said, despite being
407+ backwards-incompatible, such a change would be unlikely to have a large impact
408+ because it would only affect the behavior of structures that, under this
409+ proposal, are not particularly useful. See
412410:ref: `pep798-alternativegenexpsemantics ` for more discussion.
413411
414412.. _pep798-examples :
@@ -759,59 +757,52 @@ a `poll in the Discourse thread
759757<https://discuss.python.org/t/pep-798-unpacking-in-comprehensions/99435/33> `__.
760758Beyond the proposal outlined above, the following were also considered:
761759
762- 1. Using explicit loops for both synchronous and asynchronous generator
763- expressions.
760+ 1. Using ``yield from `` for unpacking in synchronous generator expressions but
761+ using an explicit loop in asynchronous generator expressions (as proposed in
762+ the original draft of this PEP).
764763
765- This strategy would have resulted in a symmetry between synchronous and
766- asynchronous generator expressions but would have prevented a
767- potentially-useful tool by disallowing delegation in the case of synchronous
768- generator expressions. One specific concern with this approach is the
769- introduction of an asymmetry between synchronous and asynchronous
770- generators, but this concern is mitigated by the fact that these asymmetries
771- already exist between synchronous and asynchronous generators more
772- generally.
764+ This strategy would have allowed unpacking in generator expressions to
765+ closely mimic a popular way of writing generators that perform this
766+ operation (using ``yield from ``), but it would also have created an
767+ asymmetry between synchronous and asynchronous versions, and also between
768+ this new syntax and ``itertools.chain `` and the double-loop version.
773769
7747702. Using ``yield from `` for unpacking in synchronous generator expressions and
775771 mimicking the behavior of ``yield from `` for unpacking in async generator
776772 expressions.
777773
778774 This strategy would also make unpacking in synchronous and asynchronous
779775 generators behave symmetrically, but it would also be more complex, enough
780- so that the cost may not be worth the benefit. As such, this PEP proposes
781- that asynchronous generator expressions using the unpacking operator should
782- not adopt semantics similar to ``yield from `` until ``yield from `` is
783- supported in asynchronous generators more generally.
776+ so that the cost may not be worth the benefit, particularly in the absence
777+ of a compelling use case for delegation.
784778
7857793. Using ``yield from `` for unpacking in synchronous generator expressions, and
786780 disallowing unpacking in asynchronous generator expressions until they
787781 support ``yield from ``.
788782
789783 This strategy could possibly reduce friction if asynchronous generator
790784 expressions do gain support for ``yield from `` in the future by making sure
791- that any decision made at that point would be fully backwards-compatible.
792- But the utility of unpacking in that context seems to outweigh the potential
793- downside of a minimally-invasive backwards-incompatible change in the future
794- if async generator expressions do receive support for ``yield from ``.
785+ that any decision made at that point would be fully backwards-compatible,
786+ but in the meantime, it would result in an even bigger discrepancy between
787+ synchronous and asynchronous generator expressions than option 1.
795788
7967894. Disallowing unpacking in all generator expressions.
797790
798791 This would retain symmetry between the two cases, but with the downside of
799- losing a very expressive form.
800-
792+ losing an expressive form and reducing symmetry between list/set
793+ comprehensions and generator expressions.
801794
802795Each of these options (including the one presented in this PEP) has its
803796benefits and drawbacks, with no option being clearly superior on all fronts.
804- The semantics proposed in :ref: `pep798-genexpsemantics ` represent a reasonable
805- compromise where unpacking in both synchronous and asynchronous generator
806- expressions mirrors common ways of writing equivalent generators currently.
807- Moreover, these subtle differences are unlikely to be impactful for common use
808- cases (for example, there is no difference for the likely most-common use case
809- of combining simple collections).
810-
811- As suggested above, this decision should be revisited in the event that
812- asynchronous generators receive support for ``yield from `` in the future, in
813- which case adjusting the semantics of unpacking in async generator expressions
814- to use ``yield from `` should be considered.
797+ The semantics proposed in :ref: `pep798-genexpsemantics ` above represent a
798+ reasonable compromise by allowing exactly the same kind of unpacking in
799+ synchronous and asynchronous generator expressions and retaining an existing
800+ property of generator expressions (that they do not delegate to subgenerators).
801+
802+ This decision should be revisited in the event that asynchronous generators
803+ receive support for ``yield from `` in the future, in which case adjusting the
804+ semantics of unpacking in generator expressions to use ``yield from `` should be
805+ considered.
815806
816807
817808Concerns and Disadvantages
0 commit comments