Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Star * operator on left vs right side of an assignment statement

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 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.

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?

like image 558
Dimitris Fasarakis Hilliard Avatar asked Feb 25 '16 19:02

Dimitris Fasarakis Hilliard


People also ask

What appears on the right side of the assignment statement?

Solution. The assignment statement is used to assign values to the variables. The variable on the left side of the assignment operator and a value on the right side.

What is the symbol for the assignment operator?

symbols “=” and “<-” are used as the assignment operator.

What is starred assignment in Python?

Starred Assignment You can do this by using slicing in Python, but the most explicit way is with starred assignments. This starred assignment is done by placing one * to the left of a variable name in a multiple assignment, and by having any iterable on the right of the assignment.

What symbol is used when assigning a value to a variable?

When you assign a variable, you use the = symbol. The name of the variable goes on the left and the value you want to store in the variable goes on the right. Here we've assigned the value 'Joe' , which is a string, to the variable first_name . Now if we want to reference that variable, we can.


1 Answers

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:

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.

(emphasis mine)

So in the first case, after executing:

*elements, = iterable

elements is always going to be a list containing all the items in the iterable.

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.

def spam(*args, **kwargs): 
    """ args and kwargs group positional and keywords respectively """

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:

elements = *iterable, 

can be viewed as:

elements = 1, 2, 3, 4, 

which is another way for a tuple to be initialized.

Do note, a list can be created by simple using elements = [*iterable] which will unpack the contents of iterable in [] and result in an assignments of the form elements = [1, 2, 3, 4].

like image 96
Dimitris Fasarakis Hilliard Avatar answered Sep 20 '22 13:09

Dimitris Fasarakis Hilliard