[Python-ideas] Generator unpacking

Andrew Barnert abarnert at yahoo.com
Mon Feb 15 01:31:31 EST 2016


On Feb 14, 2016, at 10:57, Georg Brandl <g.brandl at gmx.net> wrote:
> 
> Assigning to Ellipsis?  Interesting idea, but I'd probably go a bit further
> in the similarity to star-assignment:
> 
>    a, b, *... = value
> 
> Ellipsis could then be a general "throw-away" lvalue.  This would make it
> possible to say
> 
>    a, ..., b, ... = some_function()
> 
> i.e. skip exactly one item in unpacking.

But we already have a general "throw-away": underscore. You can already write "a, _, b, _ = it" and it will unpack 4 values and throw away 2 of them. And you can also write "a, b, *_ = it" to unpack 2 or more values and throw away all but the first 2. And, for that matter, "a, *_, b= it".

There's nothing special about the underscore--you could get the same effect by writing "a, dummy, b, evendummier = it"--but it's conventional.

Anyway, what people are looking for in this thread is almost the exact opposite: they don't want to unpack the value and throw it away, they want to leave the value there for later unpacking. (Of course for collections, there's no such distinction, but for iterators there is.)

>> Although again, the main downside would be that "..." here means something
>> rather different from what it means as a subscript element.
> 
> Keep in mind that Ellipsis is also a legal rvalue anywhere else.  I.e.
> this would be legal (and a no-op):
> 
>    ... = ...

With your version, where ... is a normal target that just ignores its value, sure. 

With the original version, where ... means "unpack 0 elements from the iterable and stop", it would presumably raise a TypeError("'ellipsis' object is not iterable").

> But thinking about it, this is also legal at the moment:
> 
>    [] = []

Yes, but that's completely different. The [] on the left isn't an expression, or even a target, but a target list with 0 targets in it. Assignment to target lists is defined recursively, so assigning to 0 targets is legal iff you're unpacking 0 values.

The fact that you have specifically [] on the right side is irrelevant. You can get the same effect by writing [] = (), or [] = {}, or [] = (i for i in range(5) if i<0). And clearly, you're not assigning to "the empty list", because each empty list created with [] is a distinct object.

Anyway, ... is a constant; it's currently illegal as a target because of the rule added in 3.0 banning assignment to a handful of special constants (..., None, etc.). If you have it a special meaning as a target, then of course that rule no longer applies.

> Interestingly, this raises:
> 
>    () = ()

This just doesn't parse, because the target-list grammar doesn't have the same special case for () as the parenthesized expression grammar. (Remember, both tuples and target lists are made by commas, not parens, and () really is a special case.)

If such a rule were added, then it would presumably mean the same thing as [] = (). But what would be the point of adding that rule? (You could argue that the inconsistency makes the language harder to remember, but it's been this way for decades, and nobody notices it until they've been using Python for years, so that's not very compelling.)



More information about the Python-ideas mailing list