This questions stems from PEP 448
-- Additional Unpacking Generalizations and is present in Python 3.5 as far as I'm aware (and not back-ported to 2.x
). Specifically, in the section Disadvantages, the following is noted:
Whilst
*elements, = iterable
causeselements
to be alist
,elements = *iterable
, causeselements
to be atuple
. The reason for this may confuse people unfamiliar with the construct.
Which does indeed hold, for iterable = [1, 2, 3, 4]
, the first case yields a list
:
>>> *elements, = iterable
>>> elements
[1, 2, 3, 4]
While for the second case a tuple
is created:
>>> elements = *iterable,
>>> elements
(1, 2, 3, 4)
Being unfamiliar with the concept, I am confused. Can anyone explain this behavior? Does the starred expression act differently depending on the side it is on?
The difference between these two cases are explained when also taking into consideration the initial PEP for extended unpacking:
PEP 3132 -- Extended iterable unpacking
.In the Abstract for that PEP we can see that:
(emphasis mine)
So in the first case, after executing:
elements
is always going to be alist
containing all the items in theiterable
.Even though it seems similar in both cases, the
*
in this case (left-side) means: catch everything that isn't assigned to a name and assign it to the starred expression. It works in a similar fashion as*args
and**kwargs
do in function definitions.The second case (right-side) is somewhat different. Here we don't have the
*
working in a "catch everything" way as much as we have it working as it usually does in function calls. It expands the contents of the iterable it is attached to. So, the statement:can be viewed as:
which is another way for a
tuple
to be initialized.Do note, a
list
can be created by simple usingelements = [*iterable]
which will unpack the contents ofiterable
in[]
and result in an assignments of the formelements = [1, 2, 3, 4]
.