@@ -97,33 +97,38 @@ equivalent to ``(x async for ait in aits() for x in ait)``.
9797Rationale
9898=========
9999
100- Combining iterable objects together into a single larger object is a common
101- task. One `StackOverflow post
100+ Combining multiple iterable objects together into a single object is a common
101+ task. For example, one `StackOverflow post
102102<https://stackoverflow.com/questions/952914/how-do-i-make-a-flat-list-out-of-a-list-of-lists> `_
103- asking about flattening a list of lists, for example, has been viewed 4.6
104- million times. Despite this being a common operation, the options currently
105- available for performing it concisely require levels of indirection that can
106- make the resulting code difficult to read and understand.
107-
108- The proposed notation is concise (avoiding the use and repetition of auxiliary
109- variables) and, we expect, intuitive and familiar to programmers familiar with
110- both comprehensions and unpacking notation (see :ref: `pep798-examples ` for
111- examples of code from the standard library that could be rewritten more clearly
112- and concisely using the proposed syntax).
113-
114- This proposal was motivated in part by a written exam in a Python programming
115- class, where several students used the notation (specifically the ``set ``
116- version) in their solutions, assuming that it already existed in Python. This
117- suggests that the notation is intuitive, even to beginners. By contrast, the
118- existing syntax ``[x for it in its for x in it] `` is one that students often
119- get wrong, the natural impulse for many students being to reverse the order of
120- the ``for `` clauses.
121-
122- Additionally, the comment section of a `Reddit post
103+ asking about flattening a list of lists has been viewed 4.6 million times, and
104+ there are several examples of code from the standard library that perform this
105+ operation (see :ref: `pep798-examples `). While Python provides a means of
106+ combining a small, known number of iterables using extended unpacking from
107+ :pep: `448 `, no comparable syntax currently exists for combining an arbitrary
108+ number of iterables.
109+
110+ This proposal represents a natural extension of the language, paralleling
111+ existing 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; this proposal extends that notion to the construction of
114+ lists that involve unpacking, making ``[*item for item in items] `` analogous to
115+ ``[*x, *y, *z] ``.
116+
117+ We expect this syntax to be intuitive and familiar to programmers already
118+ comfortable with both comprehensions and unpacking notation. This proposal was
119+ motivated in part by a written exam in a Python programming class, where
120+ several students used the proposed notation (specifically the ``set `` version)
121+ in their solutions, assuming that it already existed in Python. This suggests
122+ that the notation represents a logical, consistent extension to Python's
123+ existing syntax. By contrast, the existing double-loop version ``[x for it in
124+ its for x in it] `` is one that students often get wrong, the natural impulse
125+ for many students being to reverse the order of the ``for `` clauses. The
126+ intuitiveness of the proposed syntax is further supported by the comment
127+ section of a `Reddit post
123128<https://old.reddit.com/r/Python/comments/1m607oi/pep_798_unpacking_in_comprehensions/> `__
124- following the publication of this PEP shows substantial support for the
125- proposal and further suggests that the syntax proposed here is legible,
126- intuitive, and useful.
129+ made following the initial publication of this PEP, which demonstrates support
130+ from a broader community.
131+
127132
128133Specification
129134=============
@@ -412,9 +417,9 @@ Code Examples
412417=============
413418
414419This section shows some illustrative examples of how small pieces of code from
415- the standard library could be rewritten to make use of this new syntax to
416- improve concision and readability. The :ref: `pep798-reference ` continues to
417- pass all tests with these replacements made.
420+ the standard library could be rewritten to make use of this new syntax. The
421+ :ref: `pep798-reference ` continues to pass all tests with these replacements
422+ made.
418423
419424Replacing Explicit Loops
420425------------------------
@@ -430,7 +435,7 @@ need for defining and referencing an auxiliary variable.
430435 comments.extend(token.comments)
431436 return comments
432437
433- # improved :
438+ # proposed :
434439 return [*token.comments for token in self]
435440
436441* From ``shutil.py ``::
@@ -441,7 +446,7 @@ need for defining and referencing an auxiliary variable.
441446 ignored_names.extend(fnmatch.filter(names, pattern))
442447 return set(ignored_names)
443448
444- # improved :
449+ # proposed :
445450 return {*fnmatch.filter(names, pattern) for pattern in patterns}
446451
447452* From ``http/cookiejar.py ``::
@@ -452,7 +457,7 @@ need for defining and referencing an auxiliary variable.
452457 cookies.extend(self._cookies_for_domain(domain, request))
453458 return cookies
454459
455- # improved :
460+ # proposed :
456461 return [
457462 *self._cookies_for_domain(domain, request)
458463 for domain in self._cookies.keys()
@@ -463,8 +468,8 @@ Replacing from_iterable and Friends
463468
464469While not always the right choice, replacing ``itertools.chain.from_iterable ``
465470and ``map `` can avoid an extra level of redirection, resulting in code that
466- follows conventional wisdom that comprehensions are more readable than
467- map/filter.
471+ follows conventional wisdom that comprehensions are generally more readable
472+ than map/filter.
468473
469474* From ``dataclasses.py ``::
470475
@@ -473,7 +478,7 @@ map/filter.
473478 itertools.chain.from_iterable(map(_get_slots, cls.__mro__[1:-1]))
474479 )
475480
476- # improved :
481+ # proposed :
477482 inherited_slots = {*_get_slots(c) for c in cls.__mro__[1:-1]}
478483
479484* From ``importlib/metadata/__init__.py ``::
@@ -483,23 +488,23 @@ map/filter.
483488 path.search(prepared) for path in map(FastPath, paths)
484489 )
485490
486- # improved :
491+ # proposed :
487492 return (*FastPath(path).search(prepared) for path in paths)
488493
489494* From ``collections/__init__.py `` (``Counter `` class)::
490495
491496 # current:
492497 return _chain.from_iterable(_starmap(_repeat, self.items()))
493498
494- # improved :
499+ # proposed :
495500 return (*_repeat(elt, num) for elt, num in self.items())
496501
497502* From ``zipfile/_path/__init__.py ``::
498503
499504 # current:
500505 parents = itertools.chain.from_iterable(map(_parents, names))
501506
502- # improved :
507+ # proposed :
503508 parents = (*_parents(name) for name in names)
504509
505510* From ``_pyrepl/_module_completer.py ``::
@@ -510,7 +515,7 @@ map/filter.
510515 for spec in specs if spec
511516 ))
512517
513- # improved :
518+ # proposed :
514519 search_locations = {
515520 *getattr(spec, 'submodule_search_locations', [])
516521 for spec in specs if spec
@@ -520,30 +525,30 @@ Replacing Double Loops in Comprehensions
520525----------------------------------------
521526
522527Replacing double loops in comprehensions avoids the need for defining and
523- referencing an auxiliary variable, reducing clutter .
528+ referencing an auxiliary variable.
524529
525530* From ``importlib/resources/readers.py ``::
526531
527532 # current:
528533 children = (child for path in self._paths for child in path.iterdir())
529534
530- # improved :
535+ # proposed :
531536 children = (*path.iterdir() for path in self._paths)
532537
533538* From ``asyncio/base_events.py ``::
534539
535540 # current:
536541 exceptions = [exc for sub in exceptions for exc in sub]
537542
538- # improved :
543+ # proposed :
539544 exceptions = [*sub for sub in exceptions]
540545
541546* From ``_weakrefset.py ``::
542547
543548 # current:
544549 return self.__class__(e for s in (self, other) for e in s)
545550
546- # improved :
551+ # proposed :
547552 return self.__class__(*s for s in (self, other))
548553
549554
@@ -817,8 +822,8 @@ this syntax was clear and intuitive, several concerns and potential downsides
817822were raised as well. This section aims to summarize those concerns.
818823
819824* **Overlap with existing alternatives: **
820- While the proposed syntax is arguably clearer and more concise, there are
821- already several ways to accomplish this same thing in Python.
825+ While the proposed syntax is arguably more concise, there are already several
826+ ways to accomplish this same thing in Python.
822827
823828* **Function call ambiguity: **
824829 Expressions like ``f(*x for x in y) `` may initially appear ambiguous, as it's
@@ -828,7 +833,7 @@ were raised as well. This section aims to summarize those concerns.
828833 may not be immediately obvious.
829834
830835* **Potential for overuse or abuse: **
831- Complex uses of unpacking in comprehensions could obscure logic that would be
836+ Complex uses of unpacking in comprehensions could obscure logic that may be
832837 clearer in an explicit loop. While this is already a concern with
833838 comprehensions more generally, the addition of ``* `` and ``** `` may make
834839 particularly complex uses even more difficult to read and understand at a
0 commit comments