Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tuple unpacking order changes values assigned

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?)

like image 536
henry Avatar asked Dec 09 '15 05:12

henry


People also ask

Do tuples change order?

As we know that in Python, tuples are immutable, thus it cannot be changed or altered.

Does the order of a tuple matter?

Answer: NO; it's horrid; x. pop(0) will do the same thing, and in any case just about any of the answers is better than using the pop() method.

What is the unpacking of tuple explain with example?

Python offers a very powerful tuple assignment tool that maps right hand side arguments into left hand side arguments. THis act of mapping together is known as unpacking of a tuple of values into a norml variable. WHereas in packing, we put values into a regular tuple by means of regular assignment.

How does tuple unpacking work in Python?

Unpacking Tuples When we put tuples on both sides of an assignment operator, a tuple unpacking operation takes place. The values on the right are assigned to the variables on the left according to their relative position in each tuple . As you can see in the above example, a will be 1 , b will be 2 , and c will be 3 .


2 Answers

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]

like image 168
Bhargav Rao Avatar answered Oct 06 '22 01:10

Bhargav Rao


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.

like image 33
eph Avatar answered Oct 06 '22 03:10

eph