Seems sensible to me. I’d write the equivalency as

On Sat, Oct 16, 2021 at 07:11 Erik Demaine <edemaine@mit.edu> wrote:
Extended unpacking notation (* and **) from PEP 448 gives us great ways to
concatenate a few iterables or dicts:

```
(*it1, *it2, *it3)  # tuple with the concatenation of three iterables
[*it1, *it2, *it3]  # list with the concatenation of three iterables
{*it1, *it2, *it3}  # set with the union of three iterables
{**dict1, **dict2, **dict3}  # dict with the combination of three dicts
# roughly equivalent to dict1 | dict2 | dict3 thanks to PEP 584
```

I propose (not for the first time) that similarly concatenating an unknown
number of iterables or dicts should be possible via comprehensions:

```
(*it for it in its)  # tuple with the concatenation of iterables in 'its'
[*it for it in its]  # list with the concatenation of iterables in 'its'
{*it for it in its}  # set with the union of iterables in 'its'
{**d for d in dicts} # dict with the combination of dicts in 'dicts'
```

The above is my attempt to argue that the proposed notation is natural:
`[*it for it in its]` is exactly analogous to `[*its[0], *its[1], ...,
*its[len(its)-1]]`.

There are other ways to do this, of course:

```
[x for it in its for x in it]
itertools.chain(*its)
sum(it for it in its, [])
functools.reduce(operator.concat, its, [])
```

But none are as concise and (to me, and hopefully others who understand *
notation) as intuitive.  For example, I recently wanted to write a recursion
like so, which accumulated a set of results from within a tree structure:

```
def recurse(node):
# base case omitted
return {*recurse(child) for child in node.children}
```

In fact, I am teaching a class and just asked a question on a written exam for
which several students wrote this exact code in their solution (which inspired
writing this message).  So I do think it's quite intuitive, even to those
relatively new to Python.

Now, on to previous proposals.  I found this thread from 2016 (!); please let
me know if there are others.

There are several arguments for and against this feature in that thread.  I'll
try to summarize:

Arguments for:

* Natural extension to PEP 448 (it's mentioned as a variant within PEP 448)

* Easy to implement: all that's needed in CPython is to *remove* some code
blocking this.

Arguments against:

* Counterintuitive (to some)

* Hard to teach

* `[...x... for x in y]` is no longer morally equivalent to
(unless `list1.append(a, b)` were equivalent to `list1.extend([a, b])`)

Above I've tried to counter the first two "against" arguments.
Some counters to the third "against" argument:

1. `[*...x... for x in y]` is equivalent to
(about as easy to teach, I'd say)

2. Maybe `list1.append(a, b)` should be equivalent to `list1.extend([a, b])`?
It is in JavaScript (`Array.push`).  And I don't see why one would expect
it to append a tuple `(a, b)`; that's what `list1.append((a, b))` is for.
I think the main argument against this is to avoid programming errors,
which is fine, but I don't see why it should hold back an advanced feature
involving both unpacking and comprehensions.

Erik
--
Erik Demaine  |  edemaine@mit.edu  |  http://erikdemaine.org/
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/7G732VMDWCRMWM4PKRG6ZMUKH7SUC7SH/
Code of Conduct: http://python.org/psf/codeofconduct/
--
--Guido (mobile)