[Python-ideas] Fwd: unpacking generalisations for list comprehension
Steven D'Aprano
steve at pearwood.info
Wed Oct 12 19:29:43 EDT 2016
On Wed, Oct 12, 2016 at 06:32:12PM +0200, Sven R. Kunze wrote:
> On 12.10.2016 17:41, Nick Coghlan wrote:
> >This particular proposal fails on the first question (as too many
> >people would expect it to mean the same thing as either "[*expr, for
> >expr in iterable]" or "[*(expr for expr in iterable)]")
>
> So, my reasoning would tell me: where have I seen * so far? *args and
> **kwargs!
And multiplication. And sequence unpacking.
> [...] is just the list constructor.
Also indexing: dict[key] or sequence[item or slice].
The list constructor would be either list(...) or possibly
list.__new__.
[...] is either a list display:
[1, 2, 3, 4]
or a list comprehension. They are not the same thing, and they don't
work the same way. The only similarity is that they use [ ] as
delimiters, just like dict and sequence indexing. That doesn't mean that
you can write:
mydict[x for x in seq if condition]
Not everything with [ ] is the same.
> So, putting those two pieces together is quite simple.
I don't see that it is simple at all. I don't see any connection between
function *args and list comprehension loop variables.
> Furthermore, your two "interpretations" would yield the very same result
> as [expr for expr in iterable] which doesn't match with my experience
> with Python so far; especially when it comes to special characters. They
> must mean something. So, a simple "no-op" would not match my expectations.
Just because something would otherwise be a no-op doesn't mean that it
therefore has to have some magical meaning. Python has a few no-ops
which are allowed, or required, by syntax but don't do anything.
pass
(x) # same as just x
+1 # no difference between literals +1 and 1
-0
func((expr for x in iterable)) # redundant parens for generator expr
There may be more.
> >but it fails on the other two grounds as well.
>
> Here I disagree with you. We use *args all the time, so we know what *
> does. I don't understand why this should not work in between brackets [...].
By this logic, *t should work... everywhere?
while *args:
try:
raise *args
except *args:
del *args
That's not how Python works. Just because syntax is common, doesn't mean
it has to work everywhere. We cannot write:
for x in import math:
...
even though importing is common.
*t doesn't work as the expression inside a list comprehension because
that's not how list comps work. To make it work requires making this a
special case and mapping
[expr for t in iterable]
to a list append, while
[*expr for t in iterable]
gets mapped to a list extend.
Its okay to want that as a special feature, but understand what you are
asking for: you're not asking for some restriction to be lifted, which
will then automatically give you the functionality you expect. You're
asking for new functionality to be added.
Sequence unpacking inside list comprehensions as a way of flattening a
sequence is completely new functionality which does not logically follow
from the current semantics of comprehensions.
> >In most uses of *-unpacking it's adding entries to a comma-delimited
> >sequence, or consuming entries in a comma delimited sequence (the
> >commas are optional in some cases, but they're still part of the
> >relevant contexts). The expansions removed the special casing of
> >functions, and made these capabilities generally available to all
> >sequence definition operations.
>
> I don't know what you mean by comma-delimited sequence. There are no
> commas. It's just a list of entries. * adds entries to this list. (At
> least from my point of view.)
Not all points of view are equally valid.
--
Steve
More information about the Python-ideas
mailing list