Seems sensible to me. I’d write the equivalency as
for x in y: answer.extend([…x…])
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.
https://mail.python.org/archives/list/python-ideas@python.org/thread/SBM3LYESPJMI3FMTMP3VQ6JKKRDHYP7A/#DE4PCVNXBQJIGFBYRB2X7JUFZT75KYFR
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
`answer = []; for x in y: answer.append(...x...)`
(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
`answer = []; for x in y: answer.extend(...x...)`
(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)