
Seems sensible to me. I’d write the equivalency as for x in y: answer.extend([…x…]) 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.
https://mail.python.org/archives/list/python-ideas@python.org/thread/SBM3LYE...
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/7G732V... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido (mobile)