[Python-ideas] Fwd: Fwd: Fwd: unpacking generalisations for list comprehension

Steven D'Aprano steve at pearwood.info
Sat Oct 15 21:05:57 EDT 2016


On Sun, Oct 16, 2016 at 12:48:36PM +1300, Greg Ewing wrote:
> Steven D'Aprano wrote:
> >Are you now supporting my argument that starring the list comprehension 
> >expression isn't meaningful?
> 
> The context it's in (a form of list display) has a clear
> meaning for a comma-separated list of values, so there
> is a reasonable interpretation that it *could* be given.

This thread is a huge, multi-day proof that people do not agree that 
this is a "reasonable" interpretation.


> >py> iterable = [(1, 'a'), (2, 'b')]
> >py> [(100, *t) for t in iterable]
> >[(100, 1, 'a'), (100, 2, 'b')]
> 
> The * there is in the context of constructing a tuple,
> not the list into which the tuple is placed.

Right: the context of the star is meaningful. We all agree that *t in a 
list display [a, b, c, ...] is meaningful; same for tuples; same for 
function calls; same for sequence unpacking for assignment.

What is not meaningful (except as a Perlish line-noise special case to 
be memorised) is *t as the list comprehension expression.

I've never disputed that we could *assert* that *t in a list comp means 
"flatten". We could assert that it means anything we like. But it 
doesn't follow from the usual meaning of sequence unpacking anywhere 
else -- that's why it is currently a SyntaxError, and that's why people 
reacted with surprise at the OP who assumed that *t would magically 
flatten his iterable. Why would you assume that? It makes no sense to me 
-- that's not how sequence unpacking works in any other context, it 
isn't how list comprehensions work.

Right from the beginning I called this "wishful thinking", and *nothing* 
since then has changed my mind. This proposal only makes even a little 
bit of sense if you imagine list comprehensions

    [*t for a in it1 for b in it2 for c in it3 ... for t in itN]

completely unrolled into a list display:

    [*t, *t, *t, *t, ... ]

but who does that? Why would you reason about your list comps like that? 
If you think about list comps as we're expected to think of them -- as 
list builders equivalent to a for-loop -- the use of *t there is 
invalid. Hence it is a SyntaxError.

You want a second way to flatten your iterables? A cryptic, mysterious, 
Perlish line-noise way? Okay, fine, but don't pretend it is sequence 
unpacking -- in the context of a list comprehension, sequence unpacking 
doesn't make sense, it is invalid. Call it something else: the new 
"flatten" operator:

    [^t for t in iterable]

for example, which magically adds an second invisible for-loop to your 
list comps:

    # expands to
    for t in iterable:
        for x in t:
            result.append(x)

Because as your own email inadvertently reinforces, if sequence 
unpacking made sense in the context of a list comprehension, it would 
already be allowed rather than a SyntaxError: it is intentionally 
prohibited because it doesn't make sense in the context of list comps.


-- 
Steve


More information about the Python-ideas mailing list