# Tuple unpacking order changes values assigned

## Question:

I think the two are identical.

``````nums = [1, 2, 0]
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
print nums  # [2, 1, 0]

nums = [1, 2, 0]
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]
print nums  # [2, 2, 1]
``````

But the results are different.
Why are the results different? (why is the second one that result?)

## Prerequisites – 2 important Points

• Lists are mutable

The main part in lists is that lists are mutable. It means that the
values of lists can be changed. This is one of the reason why you are
facing the trouble. Refer the docs for more info

• Order of Evaluation

The other part is that while unpacking a tuple, the evaluation starts
from left to right. Refer the docs for more info

## Introduction

when you do `a,b = c,d` the values of `c` and `d` are first stored. Then starting from the left hand side, the value of `a` is first changed to `c` and then the value of `b` is changed to `d`.

The catch here is that if there are any side effects to the location of `b` while changing the value of `a`, then `d` is assigned to the later `b`, which is the `b` affected by the side effect of `a`.

## Use Case

Now coming to your problem

In the first case,

``````nums = [1, 2, 0]
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
``````

`nums[0]` is initially `1` and `nums[nums[0]]` is `2` because it evaluates to `nums[1]`. Hence 1,2 is now stored into memory.

Now tuple unpacking happens from left hand side, so

``````nums[nums[0]] = nums[1] = 1   # NO side Effect.
nums[0] = 2
``````

hence `print nums` will print `[2, 1, 0]`

However in this case

``````nums = [1, 2, 0]
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]
``````

`nums[nums[0]], nums[0]` puts 2,1 on the stack just like the first case.

However on the left hand side, that is `nums[0], nums[nums[0]]`, the changing of `nums[0]` has a side effect as it is used as the index in `nums[nums[0]]`. Thus

``````nums[0] = 2
nums[nums[0]] = nums[2] = 1  # NOTE THAT nums[0] HAS CHANGED
``````

`nums[1]` remains unchanged at value `2`. hence `print nums` will print `[2, 2, 1]`

It’s because of that python assignment priority is left to right.So in following code:

`````` nums = [1, 2, 0]
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
``````

It first assigned the `nums[0]` to `nums[nums[0]]` means `nums[1]==1` and then since lists are mutable objects the nums would be :

``````[1,1,0]
``````

and then `nums[nums[0]]` will be assigned to `nums[0]` which means `nums[0]==2` and :

``````nums = [2,1,0]
``````

And like so for second part.

Note that the important point here is that list objects are mutable and when you change it in a segment of code it can be change in-place. thus it will affect of the rest of the code.

Evaluation order

Python evaluates expressions from left to right. Notice that while evaluating an assignment, the right-hand side is evaluated before the left-hand side.

In the first example, what happens is nums[1] gets set to 1, and then nums[0] gets set to 2, as you might expect.

In the second example, nums[0] gets set to 2, and then nums[2] gets set to 1. This is because, in this case, the left hand side nums[nums[0]] is really referencing nums[2] when the assignment happens, because nums[0] had just been set to 2.

You can define a class to track the process:

``````class MyList(list):
def __getitem__(self, key):
print('get ' + str(key))
return super(MyList, self).__getitem__(key)
def __setitem__(self, key, value):
print('set ' + str(key) + ', ' + str(value))
return super(MyList, self).__setitem__(key, value)
``````

For the first method:

``````nums = MyList([1, 2, 0])
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
``````

the output is:

``````get 0
get 0
get 1
get 0
set 1, 1
set 0, 2
``````

While the second method:

``````nums = MyList([1, 2, 0])
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]
``````

the output is:

``````get 0
get 1
get 0
set 0, 2
get 0
set 2, 1
``````

In both methods, the first three lines are related to tuple generation while the last three lines are related to assignments. Right hand side tuple of the first method is `(1, 2)` and the second method is `(2, 1)`.

In the assignment stage, first method get `nums[0]` which is `1`, and set `nums[1] = 1`, then `nums[0] = 2`, second method assign `nums[0] = 2`, then get `nums[0]` which is `2`, and finally set `nums[2] = 1`.