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

Sjoerd Job Postmus sjoerdjob at sjoerdjob.com
Thu Oct 13 16:40:19 EDT 2016


After having followed this thread for a while, it occured to me that the
reason that the idea is confusing, is because the spelling is confusing.

I think the suggested spelling (`*`) is the confusing part. If it were
to be spelled `from ` instead, it would be less confusing.

Consider this:

    g = (f(t) for t in iterable)

is "merely" sugar for

    def gen():
        for t in iterable:
            yield f(t)
    g = gen()

Likewise,

    l = [f(t) for t in iterable]

can be seen as sugar for

    def gen():
        for t in iterable:
            yield f(t)
    l = list(gen())

Now the suggested spelling

    l = [*f(t) for t in iterable]

is very confusing, from what I understand: what does the `*` even mean
here.

However, consider the following spelling:

    l = [from f(t) for t in iterable]

To me, it does not seem far-fetched that this would mean:

    def gen():
        for t in iterable:
            yield from f(t)
    l = list(gen())

It follows the "rule" quite well: given a generator display, everything
before the first "for" gets placed after "yield ", and all the
`for`/`if`s are expanded to suites.

Now I'm not sure if I'm a fan of the idea, but I think that at least the
`from `-spelling is less confusing than the `*`-spelling.

(Unless I totally misunderstood what the `*`-spelling was about, given
how confusing it supposedly is. Maybe it confused me.)

On Fri, Oct 14, 2016 at 03:55:46AM +1100, Steven D'Aprano wrote:
> On Thu, Oct 13, 2016 at 04:34:49PM +0200, Martti Kühne wrote:
> 
> > > If I had seen a list comprehension with an unpacked loop variable:
> > >
> > >     [t for t in [(1, 'a'), (2, 'b'), (3, 'c')]]
> 
> Marttii, somehow you have lost the leading * when quoting me. What I 
> actually wrote was:
> 
>     [*t for t in [(1, 'a'), (2, 'b'), (3, 'c')]]
> 
> 
> > As it happens, python does have an external consumption operation that
> > happens externally with an iteration implied:
> > 
> > for t in iterable:
> >     yield t
> 
> If you replace the t with *t, you get a syntax error:
> 
> 
> py> def gen():
> ...     for t in [(1, 'a'), (2, 'b'), (3, 'c')]:
> ...             yield *t
>   File "<stdin>", line 3
>     yield *t
>           ^
> SyntaxError: invalid syntax
> 
> Even if it was allowed, what would it mean? It could only mean "unpack 
> the sequence t, and collect the values into a tuple; then yield the 
> tuple".
> 
> 
>  
> > For your example [t for t in [(1, 'a'), (2, 'b'), (3, 'c')]] that would mean:
> > 
> > for t in [(1, 'a'), (2, 'b'), (3, 'c')]:
> >     yield t
> > 
> > And accordingly, for the latter case [*t for t in [(1, 'a'), (2, 'b'),
> > (3, 'c')]] it would be:
> > 
> > for item in [(1, 'a'), (2, 'b'), (3, 'c')]:
> >     for t in item:
> >         yield t
> 
> No it wouldn't. Where does the second for loop come from? The list 
> comprehension shown only has one loop, not nested loops.
> 
> 
> 
> -- 
> Steve
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/


More information about the Python-ideas mailing list