Why does splatting create a tuple on the rhs but a list on the lhs? Why does splatting create a tuple on the rhs but a list on the lhs? python-3.x python-3.x

Why does splatting create a tuple on the rhs but a list on the lhs?


The fact that you get a tuple on the RHS has nothing to do with the splat. The splat just unpacks your map iterator. What you unpack it into is decided by the fact that you've used tuple syntax:

*whatever,

instead of list syntax:

[*whatever]

or set syntax:

{*whatever}

You could have gotten a list or a set. You just told Python to make a tuple.


On the LHS, a splatted assignment target always produces a list. It doesn't matter whether you use "tuple-style"

*target, = whatever

or "list-style"

[*target] = whatever

syntax for the target list. The syntax looks a lot like the syntax for creating a list or tuple, but target list syntax is an entirely different thing.

The syntax you're using on the left was introduced in PEP 3132, to support use cases like

first, *rest = iterable

In an unpacking assignment, elements of an iterable are assigned to unstarred targets by position, and if there's a starred target, any extras are stuffed into a list and assigned to that target. A list was chosen instead of a tuple to make further processing easier. Since you have only a starred target in your example, all items go in the "extras" list assigned to that target.


This is specified in PEP-0448 disadvantages

Whilst *elements, = iterable causes elements to be a list, elements = *iterable, causes elements to be a tuple. The reason for this may confuse people unfamiliar with the construct.

Also as per: PEP-3132 specification

This PEP proposes a change to iterable unpacking syntax, allowing to specify a "catch-all" name which will be assigned a list of all items not assigned to a "regular" name.

Also mentioned here: Python-3 exprlists

Except when part of a list or set display, an expression list containing at least one comma yields a tuple.
The trailing comma is required only to create a single tuple (a.k.a. a singleton); it is optional in all other cases. A single expression without a trailing comma doesn’t create a tuple, but rather yields the value of that expression. (To create an empty tuple, use an empty pair of parentheses: ().)

This might also be seen in a simpler example here, where elements in a list

In [27]: *elements, = range(6)                                                                                                                                                      In [28]: elements                                                                                                                                                                   Out[28]: [0, 1, 2, 3, 4, 5]

and here, where elements is a tuple

In [13]: elements = *range(6),                                                                                                                                                      In [14]: elements                                                                                                                                                                   Out[14]: (0, 1, 2, 3, 4, 5)

From what I could understand from the comments and the other answers:

  • The first behaviour is to keep in-line with the existing arbitrary argument lists used in functions ie.*args

  • The second behaviour is to be able to use the variables on LHS further down in the evaluation, so making it a list, a mutable value rather than a tuple makes more sense


There is an indication of the reason why at the end of PEP 3132 -- Extended Iterable Unpacking:

Acceptance

After a short discussion on the python-3000 list [1], thePEP was accepted by Guido in its current form. Possible changesdiscussed were:

[...]

Make the starred target a tuple instead of a list. This would beconsistent with a function's *args, but make further processing of theresult harder.

[1] https://mail.python.org/pipermail/python-3000/2007-May/007198.html

So, the advantage of having a mutable list instead of an immutable tuple seems to be the reason.