python a,b = b,a implementation? How is it different from C++ swap function?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
15
down vote

favorite
1












I met this problem when I want to try a python version of:
https://leetcode.com/problems/first-missing-positive/discuss/17071/My-short-c++-solution-O(1)-space-and-O(n)-time



I am not sure why a[0], a[a[0]] = a[a[0]], a[0] this one does not do the swap?



>>> nums
[2, 1, 0]
>>> a = [2,1,0]
>>> a[0], a[a[0]] = a[a[0]], a[0]
>>> a
[2, 1, 0]
>>> a[0]
2
>>> a[0],a[2] = a[2], a[0]
>>> a
[0, 1, 2]


My guess is that the implementation of a, b = b, a syntax is something like:



tmp = a[0] (tmp = 2)
a[0] = a[a[0]] (a[0] = a[2] = 0)
a[a[0]] = tmp (a[a[0]] = a[0] = tmp = 2)


Then I checked the implementation of swap function in C++. I know nothing about C++, but it looks like the idea is the same
:
http://www.cplusplus.com/reference/algorithm/swap/



The behavior of these function templates is equivalent to:
template <class T> void swap (T& a, T& b)

T c(std::move(a)); a=std::move(b); b=std::move(c);

template <class T, size_t N> void swap (T (&a)[N], T (&b)[N])

for (size_t i = 0; i<N; ++i) swap (a[i],b[i]);



we have c = a, then a = b and b = a
So why C++ swap function does not have this problem?
And how to write this kind of swap function in a pythonic way?










share|improve this question



















  • 1




    if you use a different list (like a = [1,2,3,4]) you will see it does change the values, but the problem is in the order of execution, so a[a[0]] points to different elements the two times its called.
    – Zinki
    Aug 21 at 13:54











  • Possible duplicate of Multiple assignment and evaluation order in Python
    – agtoever
    Aug 21 at 14:04










  • Fun fact: if you use a = [2,3,4] instead, you get "List assignment index out of range".
    – molbdnilo
    Aug 21 at 14:08










  • I believe there's a problem somewhat related to the "sequence points" problem in C++, in that your left-hand side both modifies and uses a[0].
    – molbdnilo
    Aug 21 at 14:26














up vote
15
down vote

favorite
1












I met this problem when I want to try a python version of:
https://leetcode.com/problems/first-missing-positive/discuss/17071/My-short-c++-solution-O(1)-space-and-O(n)-time



I am not sure why a[0], a[a[0]] = a[a[0]], a[0] this one does not do the swap?



>>> nums
[2, 1, 0]
>>> a = [2,1,0]
>>> a[0], a[a[0]] = a[a[0]], a[0]
>>> a
[2, 1, 0]
>>> a[0]
2
>>> a[0],a[2] = a[2], a[0]
>>> a
[0, 1, 2]


My guess is that the implementation of a, b = b, a syntax is something like:



tmp = a[0] (tmp = 2)
a[0] = a[a[0]] (a[0] = a[2] = 0)
a[a[0]] = tmp (a[a[0]] = a[0] = tmp = 2)


Then I checked the implementation of swap function in C++. I know nothing about C++, but it looks like the idea is the same
:
http://www.cplusplus.com/reference/algorithm/swap/



The behavior of these function templates is equivalent to:
template <class T> void swap (T& a, T& b)

T c(std::move(a)); a=std::move(b); b=std::move(c);

template <class T, size_t N> void swap (T (&a)[N], T (&b)[N])

for (size_t i = 0; i<N; ++i) swap (a[i],b[i]);



we have c = a, then a = b and b = a
So why C++ swap function does not have this problem?
And how to write this kind of swap function in a pythonic way?










share|improve this question



















  • 1




    if you use a different list (like a = [1,2,3,4]) you will see it does change the values, but the problem is in the order of execution, so a[a[0]] points to different elements the two times its called.
    – Zinki
    Aug 21 at 13:54











  • Possible duplicate of Multiple assignment and evaluation order in Python
    – agtoever
    Aug 21 at 14:04










  • Fun fact: if you use a = [2,3,4] instead, you get "List assignment index out of range".
    – molbdnilo
    Aug 21 at 14:08










  • I believe there's a problem somewhat related to the "sequence points" problem in C++, in that your left-hand side both modifies and uses a[0].
    – molbdnilo
    Aug 21 at 14:26












up vote
15
down vote

favorite
1









up vote
15
down vote

favorite
1






1





I met this problem when I want to try a python version of:
https://leetcode.com/problems/first-missing-positive/discuss/17071/My-short-c++-solution-O(1)-space-and-O(n)-time



I am not sure why a[0], a[a[0]] = a[a[0]], a[0] this one does not do the swap?



>>> nums
[2, 1, 0]
>>> a = [2,1,0]
>>> a[0], a[a[0]] = a[a[0]], a[0]
>>> a
[2, 1, 0]
>>> a[0]
2
>>> a[0],a[2] = a[2], a[0]
>>> a
[0, 1, 2]


My guess is that the implementation of a, b = b, a syntax is something like:



tmp = a[0] (tmp = 2)
a[0] = a[a[0]] (a[0] = a[2] = 0)
a[a[0]] = tmp (a[a[0]] = a[0] = tmp = 2)


Then I checked the implementation of swap function in C++. I know nothing about C++, but it looks like the idea is the same
:
http://www.cplusplus.com/reference/algorithm/swap/



The behavior of these function templates is equivalent to:
template <class T> void swap (T& a, T& b)

T c(std::move(a)); a=std::move(b); b=std::move(c);

template <class T, size_t N> void swap (T (&a)[N], T (&b)[N])

for (size_t i = 0; i<N; ++i) swap (a[i],b[i]);



we have c = a, then a = b and b = a
So why C++ swap function does not have this problem?
And how to write this kind of swap function in a pythonic way?










share|improve this question















I met this problem when I want to try a python version of:
https://leetcode.com/problems/first-missing-positive/discuss/17071/My-short-c++-solution-O(1)-space-and-O(n)-time



I am not sure why a[0], a[a[0]] = a[a[0]], a[0] this one does not do the swap?



>>> nums
[2, 1, 0]
>>> a = [2,1,0]
>>> a[0], a[a[0]] = a[a[0]], a[0]
>>> a
[2, 1, 0]
>>> a[0]
2
>>> a[0],a[2] = a[2], a[0]
>>> a
[0, 1, 2]


My guess is that the implementation of a, b = b, a syntax is something like:



tmp = a[0] (tmp = 2)
a[0] = a[a[0]] (a[0] = a[2] = 0)
a[a[0]] = tmp (a[a[0]] = a[0] = tmp = 2)


Then I checked the implementation of swap function in C++. I know nothing about C++, but it looks like the idea is the same
:
http://www.cplusplus.com/reference/algorithm/swap/



The behavior of these function templates is equivalent to:
template <class T> void swap (T& a, T& b)

T c(std::move(a)); a=std::move(b); b=std::move(c);

template <class T, size_t N> void swap (T (&a)[N], T (&b)[N])

for (size_t i = 0; i<N; ++i) swap (a[i],b[i]);



we have c = a, then a = b and b = a
So why C++ swap function does not have this problem?
And how to write this kind of swap function in a pythonic way?







python algorithm






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Aug 21 at 13:51









Rakete1111

32.6k975110




32.6k975110










asked Aug 21 at 13:46









RioAraki

1465




1465







  • 1




    if you use a different list (like a = [1,2,3,4]) you will see it does change the values, but the problem is in the order of execution, so a[a[0]] points to different elements the two times its called.
    – Zinki
    Aug 21 at 13:54











  • Possible duplicate of Multiple assignment and evaluation order in Python
    – agtoever
    Aug 21 at 14:04










  • Fun fact: if you use a = [2,3,4] instead, you get "List assignment index out of range".
    – molbdnilo
    Aug 21 at 14:08










  • I believe there's a problem somewhat related to the "sequence points" problem in C++, in that your left-hand side both modifies and uses a[0].
    – molbdnilo
    Aug 21 at 14:26












  • 1




    if you use a different list (like a = [1,2,3,4]) you will see it does change the values, but the problem is in the order of execution, so a[a[0]] points to different elements the two times its called.
    – Zinki
    Aug 21 at 13:54











  • Possible duplicate of Multiple assignment and evaluation order in Python
    – agtoever
    Aug 21 at 14:04










  • Fun fact: if you use a = [2,3,4] instead, you get "List assignment index out of range".
    – molbdnilo
    Aug 21 at 14:08










  • I believe there's a problem somewhat related to the "sequence points" problem in C++, in that your left-hand side both modifies and uses a[0].
    – molbdnilo
    Aug 21 at 14:26







1




1




if you use a different list (like a = [1,2,3,4]) you will see it does change the values, but the problem is in the order of execution, so a[a[0]] points to different elements the two times its called.
– Zinki
Aug 21 at 13:54





if you use a different list (like a = [1,2,3,4]) you will see it does change the values, but the problem is in the order of execution, so a[a[0]] points to different elements the two times its called.
– Zinki
Aug 21 at 13:54













Possible duplicate of Multiple assignment and evaluation order in Python
– agtoever
Aug 21 at 14:04




Possible duplicate of Multiple assignment and evaluation order in Python
– agtoever
Aug 21 at 14:04












Fun fact: if you use a = [2,3,4] instead, you get "List assignment index out of range".
– molbdnilo
Aug 21 at 14:08




Fun fact: if you use a = [2,3,4] instead, you get "List assignment index out of range".
– molbdnilo
Aug 21 at 14:08












I believe there's a problem somewhat related to the "sequence points" problem in C++, in that your left-hand side both modifies and uses a[0].
– molbdnilo
Aug 21 at 14:26




I believe there's a problem somewhat related to the "sequence points" problem in C++, in that your left-hand side both modifies and uses a[0].
– molbdnilo
Aug 21 at 14:26












4 Answers
4






active

oldest

votes

















up vote
5
down vote



accepted










To understand this you need to go inside the implementation using dis.



First lets consider a simple swap function:



from dis import dis

def swap(i, j):
i, j = j, i

dis(swap)


Output Byte Code:



4 0 LOAD_FAST 1 (j)
2 LOAD_FAST 0 (i)
4 ROT_TWO
6 STORE_FAST 0 (i)
8 STORE_FAST 1 (j)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE


You can see that there is ROT_TWO which means that




Swaps the two top-most stack items.




This ROT_TWO is mainly responsible for the swapping.



Now coming to your question:



Lets take the example which is working:



from dis import dis

def swap():
a = [2, 1]
a[0], a[1] = a[1], a[0]

dis(swap)


Output Byte Code :



 4 0 LOAD_CONST 1 (2)
2 LOAD_CONST 2 (1)
4 BUILD_LIST 2
6 STORE_FAST 0 (a)

5 8 LOAD_FAST 0 (a)
10 LOAD_CONST 2 (1)
12 BINARY_SUBSCR
14 LOAD_FAST 0 (a)
16 LOAD_CONST 3 (0)
18 BINARY_SUBSCR
20 ROT_TWO
22 LOAD_FAST 0 (a)
24 LOAD_CONST 3 (0)
26 STORE_SUBSCR
28 LOAD_FAST 0 (a)
30 LOAD_CONST 2 (1)
32 STORE_SUBSCR
34 LOAD_CONST 0 (None)
36 RETURN_VALUE


Output byte code is similar to what we have when it is a simple swap function.



But when the code is changed:



from dis import dis

def swap():
a = [1, 0]
a[0], a[a[0]] = a[a[0]], a[0]
dis(swap)

swap()


Output is



 4 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (0)
4 BUILD_LIST 2
6 STORE_FAST 0 (a)

5 8 LOAD_FAST 0 (a)
10 LOAD_FAST 0 (a)
12 LOAD_CONST 2 (0)
14 BINARY_SUBSCR
16 BINARY_SUBSCR
18 LOAD_FAST 0 (a)
20 LOAD_CONST 2 (0)
22 BINARY_SUBSCR
24 ROT_TWO
26 LOAD_FAST 0 (a)
28 LOAD_CONST 2 (0)
30 STORE_SUBSCR
32 LOAD_FAST 0 (a)
34 LOAD_FAST 0 (a)
36 LOAD_CONST 2 (0)
38 BINARY_SUBSCR
40 STORE_SUBSCR
42 LOAD_CONST 0 (None)
44 RETURN_VALUE


You can see the output byte code that top two items are the same. Hence it doesn't swap






share|improve this answer






















  • I think Swaps the two top-most stack items. is still not an implementation detail. How do these two items swap?
    – Sraw
    Aug 21 at 14:03











  • @Sraw check my updated explanation. I think it would make more sense now
    – argo
    Aug 21 at 14:23

















up vote
7
down vote













This kind of the behaviour is indeed related to the way Python evaluates the expression of the type



a,b=b,a


In fact, what Python does is first it "prepares" the values of the right side by creating a tuple (b,a). Then this tuple is unpacked and assigned to the variables in the reverse order.



It is important to note that the temporary tuple is created using values of variables (de facto copies of values), not references to the variables (you can read here about the difference between passing by value and by reference).



To break down the example with reference types (lists) that you used:



a = [2,1,0] 
a[0], a[a[0]] = a[a[0]], a[0]



  1. a[a[0]] takes the value from the a[0] element (equal to 2) of the list a (value 0).


  2. a[0] is 2 hence the tuple created is (0,2)

  3. Tuple (0,2) is unpacked and 0 replaces 2 in the list (0th element).

  4. Now, a[a[0]] can be read as: take 0th element of list a (which is currently 0) and then replace the value in the list at that place with 2 from tuple unpacking (now 0 is replaced by 2 - which make the operation look like it does nothing to the list).

As suggested in the answer from von Oak changing the order helps because the step from the point 4. above does not replace the value again.






share|improve this answer



























    up vote
    1
    down vote













    Python and C++ are different languages with different rules. That's largely the reason why superficially similar constructs behave differently in these languages.



    You cannot write a generic swap in Python that would work with input like a[0], a[a[0]]. This is not a problem. You shouldn't ever try to swap such things in any language in order to avoid confusion and improve your chances for future employment as a programmer.



    If you absolutely positively need to swap array elements indexed by elements of the same array, you can do it like so in Python:



    p, q, a[p], a[q] = index0, index1, a[q], a[p]


    where index0 and index1 may be any expression involving a[i], a[a[i]], a[a[a[i]]] or anything similar. For example



    p, q, a[p], a[q] = a[0], a[a[0]], a[q], a[p]


    works.






    share|improve this answer





























      up vote
      0
      down vote













      It's easy to think about it also only on the paper (e.g. at the job interview) and you don't need to debug or disassemble code to bytecode for understanding.



      I also think it hasn't anything to do with the implementation of swap function in C++. These are unrelated things.



      What you only need to know is that the right side is completely evaluated first and then the values from the right side of the expression are assigned to the values on the left side in the order from the left to the right. Sophros answered it right way I only expand the idea further and in more detail.



      Imagine the first case. We have:



      a = [2,1,0]

      a[0], a[a[0]] = a[a[0]], a[0]


      When we start to execute this code, the right side evaluates first, so we will have



      a[0], a[a[0]] = a[a[0]], a[0] # a[a[0]] == 0, a[0] == 2, a == [2, 1, 0]


      On the right side, we have tuple (0, 2) and a is still [2, 1, 0]



      Next, we start to assign to the left side of the expression from the left, so to the a[0] we assign the first item from the tuple, which is 0. Now we have



      a[0], a[a[0]] = (0, 2) # a[0] == 0, a == [0, 1, 0]


      And now we execute the last part of the assignment, which is to a[a[0]] assign 2. But a[0] is now 0, so after reduction we assign to a[0] value 2. Therefore values after the last assignment are



      a[0], a[a[0]] = (0, 2) # a[a[0]] == 2, a == [2, 1, 0]


      Which seems, that nothing changed and values didn't swap, but as is apparent from above a was [2,1,0], then [0,1,0] and lastly again [2,1,0]. So it seems, nothing changed and swap doesn't work.



      And now the second case, where we only change the order of variables in the expression:



      a = [2,1,0]

      a[a[0]], a[0] = a[0], a[a[0]]


      When we start to execute this code, the right side evaluates first, so we will have



      a[a[0]], a[0] = a[0], a[a[0]] # a[0] == 2, a[a[0]] == 0, a == [2, 1, 0]


      On the right side, we have tuple (2, 0) and a is still [2, 1, 0]



      Next, we start to assign to the left side of the expression from the left, so to the a[a[0]] we assign the first item from the tuple, which is 2. a[0] is 2, so after reduction, we assign to a[2] value 2. Now we have



      a[a[0]], a[0] = (2, 0) # a[a[0]] == 2, a == [2, 1, 2]


      And now we execute the last part of the assignment, which is to a[0] assign 0. Therefore values after the last assignment are



      a[a[0]], a[0] = (2, 0) # a[0] == 0, a == [0, 1, 2]


      Now this works as expected.



      So it is necessary also think about the order when you have dependent variables in your swap expression. As dependent variables I mean that in the first case we have on the left side a[0], a[a[0]] that means a[0] change it's value and a[a[0]] use this changed value, which leads to unwanted behavior.



      Finally, regardless of the programming language, it's better not to use dependent variables (array index for another array index etc.), when you want to swap their values.






      share|improve this answer






















      • What about swapping a[a[a[0]]] and a[a[0]]? Would it work?
        – n.m.
        Aug 21 at 14:22










      • I vastly extended my answer, so now you can try your example as the exercise:-)
        – von Oak
        Aug 21 at 23:30










      Your Answer





      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      convertImagesToLinks: true,
      noModals: false,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













       

      draft saved


      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51950193%2fpython-a-b-b-a-implementation-how-is-it-different-from-c-swap-function%23new-answer', 'question_page');

      );

      Post as a guest






























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      5
      down vote



      accepted










      To understand this you need to go inside the implementation using dis.



      First lets consider a simple swap function:



      from dis import dis

      def swap(i, j):
      i, j = j, i

      dis(swap)


      Output Byte Code:



      4 0 LOAD_FAST 1 (j)
      2 LOAD_FAST 0 (i)
      4 ROT_TWO
      6 STORE_FAST 0 (i)
      8 STORE_FAST 1 (j)
      10 LOAD_CONST 0 (None)
      12 RETURN_VALUE


      You can see that there is ROT_TWO which means that




      Swaps the two top-most stack items.




      This ROT_TWO is mainly responsible for the swapping.



      Now coming to your question:



      Lets take the example which is working:



      from dis import dis

      def swap():
      a = [2, 1]
      a[0], a[1] = a[1], a[0]

      dis(swap)


      Output Byte Code :



       4 0 LOAD_CONST 1 (2)
      2 LOAD_CONST 2 (1)
      4 BUILD_LIST 2
      6 STORE_FAST 0 (a)

      5 8 LOAD_FAST 0 (a)
      10 LOAD_CONST 2 (1)
      12 BINARY_SUBSCR
      14 LOAD_FAST 0 (a)
      16 LOAD_CONST 3 (0)
      18 BINARY_SUBSCR
      20 ROT_TWO
      22 LOAD_FAST 0 (a)
      24 LOAD_CONST 3 (0)
      26 STORE_SUBSCR
      28 LOAD_FAST 0 (a)
      30 LOAD_CONST 2 (1)
      32 STORE_SUBSCR
      34 LOAD_CONST 0 (None)
      36 RETURN_VALUE


      Output byte code is similar to what we have when it is a simple swap function.



      But when the code is changed:



      from dis import dis

      def swap():
      a = [1, 0]
      a[0], a[a[0]] = a[a[0]], a[0]
      dis(swap)

      swap()


      Output is



       4 0 LOAD_CONST 1 (1)
      2 LOAD_CONST 2 (0)
      4 BUILD_LIST 2
      6 STORE_FAST 0 (a)

      5 8 LOAD_FAST 0 (a)
      10 LOAD_FAST 0 (a)
      12 LOAD_CONST 2 (0)
      14 BINARY_SUBSCR
      16 BINARY_SUBSCR
      18 LOAD_FAST 0 (a)
      20 LOAD_CONST 2 (0)
      22 BINARY_SUBSCR
      24 ROT_TWO
      26 LOAD_FAST 0 (a)
      28 LOAD_CONST 2 (0)
      30 STORE_SUBSCR
      32 LOAD_FAST 0 (a)
      34 LOAD_FAST 0 (a)
      36 LOAD_CONST 2 (0)
      38 BINARY_SUBSCR
      40 STORE_SUBSCR
      42 LOAD_CONST 0 (None)
      44 RETURN_VALUE


      You can see the output byte code that top two items are the same. Hence it doesn't swap






      share|improve this answer






















      • I think Swaps the two top-most stack items. is still not an implementation detail. How do these two items swap?
        – Sraw
        Aug 21 at 14:03











      • @Sraw check my updated explanation. I think it would make more sense now
        – argo
        Aug 21 at 14:23














      up vote
      5
      down vote



      accepted










      To understand this you need to go inside the implementation using dis.



      First lets consider a simple swap function:



      from dis import dis

      def swap(i, j):
      i, j = j, i

      dis(swap)


      Output Byte Code:



      4 0 LOAD_FAST 1 (j)
      2 LOAD_FAST 0 (i)
      4 ROT_TWO
      6 STORE_FAST 0 (i)
      8 STORE_FAST 1 (j)
      10 LOAD_CONST 0 (None)
      12 RETURN_VALUE


      You can see that there is ROT_TWO which means that




      Swaps the two top-most stack items.




      This ROT_TWO is mainly responsible for the swapping.



      Now coming to your question:



      Lets take the example which is working:



      from dis import dis

      def swap():
      a = [2, 1]
      a[0], a[1] = a[1], a[0]

      dis(swap)


      Output Byte Code :



       4 0 LOAD_CONST 1 (2)
      2 LOAD_CONST 2 (1)
      4 BUILD_LIST 2
      6 STORE_FAST 0 (a)

      5 8 LOAD_FAST 0 (a)
      10 LOAD_CONST 2 (1)
      12 BINARY_SUBSCR
      14 LOAD_FAST 0 (a)
      16 LOAD_CONST 3 (0)
      18 BINARY_SUBSCR
      20 ROT_TWO
      22 LOAD_FAST 0 (a)
      24 LOAD_CONST 3 (0)
      26 STORE_SUBSCR
      28 LOAD_FAST 0 (a)
      30 LOAD_CONST 2 (1)
      32 STORE_SUBSCR
      34 LOAD_CONST 0 (None)
      36 RETURN_VALUE


      Output byte code is similar to what we have when it is a simple swap function.



      But when the code is changed:



      from dis import dis

      def swap():
      a = [1, 0]
      a[0], a[a[0]] = a[a[0]], a[0]
      dis(swap)

      swap()


      Output is



       4 0 LOAD_CONST 1 (1)
      2 LOAD_CONST 2 (0)
      4 BUILD_LIST 2
      6 STORE_FAST 0 (a)

      5 8 LOAD_FAST 0 (a)
      10 LOAD_FAST 0 (a)
      12 LOAD_CONST 2 (0)
      14 BINARY_SUBSCR
      16 BINARY_SUBSCR
      18 LOAD_FAST 0 (a)
      20 LOAD_CONST 2 (0)
      22 BINARY_SUBSCR
      24 ROT_TWO
      26 LOAD_FAST 0 (a)
      28 LOAD_CONST 2 (0)
      30 STORE_SUBSCR
      32 LOAD_FAST 0 (a)
      34 LOAD_FAST 0 (a)
      36 LOAD_CONST 2 (0)
      38 BINARY_SUBSCR
      40 STORE_SUBSCR
      42 LOAD_CONST 0 (None)
      44 RETURN_VALUE


      You can see the output byte code that top two items are the same. Hence it doesn't swap






      share|improve this answer






















      • I think Swaps the two top-most stack items. is still not an implementation detail. How do these two items swap?
        – Sraw
        Aug 21 at 14:03











      • @Sraw check my updated explanation. I think it would make more sense now
        – argo
        Aug 21 at 14:23












      up vote
      5
      down vote



      accepted







      up vote
      5
      down vote



      accepted






      To understand this you need to go inside the implementation using dis.



      First lets consider a simple swap function:



      from dis import dis

      def swap(i, j):
      i, j = j, i

      dis(swap)


      Output Byte Code:



      4 0 LOAD_FAST 1 (j)
      2 LOAD_FAST 0 (i)
      4 ROT_TWO
      6 STORE_FAST 0 (i)
      8 STORE_FAST 1 (j)
      10 LOAD_CONST 0 (None)
      12 RETURN_VALUE


      You can see that there is ROT_TWO which means that




      Swaps the two top-most stack items.




      This ROT_TWO is mainly responsible for the swapping.



      Now coming to your question:



      Lets take the example which is working:



      from dis import dis

      def swap():
      a = [2, 1]
      a[0], a[1] = a[1], a[0]

      dis(swap)


      Output Byte Code :



       4 0 LOAD_CONST 1 (2)
      2 LOAD_CONST 2 (1)
      4 BUILD_LIST 2
      6 STORE_FAST 0 (a)

      5 8 LOAD_FAST 0 (a)
      10 LOAD_CONST 2 (1)
      12 BINARY_SUBSCR
      14 LOAD_FAST 0 (a)
      16 LOAD_CONST 3 (0)
      18 BINARY_SUBSCR
      20 ROT_TWO
      22 LOAD_FAST 0 (a)
      24 LOAD_CONST 3 (0)
      26 STORE_SUBSCR
      28 LOAD_FAST 0 (a)
      30 LOAD_CONST 2 (1)
      32 STORE_SUBSCR
      34 LOAD_CONST 0 (None)
      36 RETURN_VALUE


      Output byte code is similar to what we have when it is a simple swap function.



      But when the code is changed:



      from dis import dis

      def swap():
      a = [1, 0]
      a[0], a[a[0]] = a[a[0]], a[0]
      dis(swap)

      swap()


      Output is



       4 0 LOAD_CONST 1 (1)
      2 LOAD_CONST 2 (0)
      4 BUILD_LIST 2
      6 STORE_FAST 0 (a)

      5 8 LOAD_FAST 0 (a)
      10 LOAD_FAST 0 (a)
      12 LOAD_CONST 2 (0)
      14 BINARY_SUBSCR
      16 BINARY_SUBSCR
      18 LOAD_FAST 0 (a)
      20 LOAD_CONST 2 (0)
      22 BINARY_SUBSCR
      24 ROT_TWO
      26 LOAD_FAST 0 (a)
      28 LOAD_CONST 2 (0)
      30 STORE_SUBSCR
      32 LOAD_FAST 0 (a)
      34 LOAD_FAST 0 (a)
      36 LOAD_CONST 2 (0)
      38 BINARY_SUBSCR
      40 STORE_SUBSCR
      42 LOAD_CONST 0 (None)
      44 RETURN_VALUE


      You can see the output byte code that top two items are the same. Hence it doesn't swap






      share|improve this answer














      To understand this you need to go inside the implementation using dis.



      First lets consider a simple swap function:



      from dis import dis

      def swap(i, j):
      i, j = j, i

      dis(swap)


      Output Byte Code:



      4 0 LOAD_FAST 1 (j)
      2 LOAD_FAST 0 (i)
      4 ROT_TWO
      6 STORE_FAST 0 (i)
      8 STORE_FAST 1 (j)
      10 LOAD_CONST 0 (None)
      12 RETURN_VALUE


      You can see that there is ROT_TWO which means that




      Swaps the two top-most stack items.




      This ROT_TWO is mainly responsible for the swapping.



      Now coming to your question:



      Lets take the example which is working:



      from dis import dis

      def swap():
      a = [2, 1]
      a[0], a[1] = a[1], a[0]

      dis(swap)


      Output Byte Code :



       4 0 LOAD_CONST 1 (2)
      2 LOAD_CONST 2 (1)
      4 BUILD_LIST 2
      6 STORE_FAST 0 (a)

      5 8 LOAD_FAST 0 (a)
      10 LOAD_CONST 2 (1)
      12 BINARY_SUBSCR
      14 LOAD_FAST 0 (a)
      16 LOAD_CONST 3 (0)
      18 BINARY_SUBSCR
      20 ROT_TWO
      22 LOAD_FAST 0 (a)
      24 LOAD_CONST 3 (0)
      26 STORE_SUBSCR
      28 LOAD_FAST 0 (a)
      30 LOAD_CONST 2 (1)
      32 STORE_SUBSCR
      34 LOAD_CONST 0 (None)
      36 RETURN_VALUE


      Output byte code is similar to what we have when it is a simple swap function.



      But when the code is changed:



      from dis import dis

      def swap():
      a = [1, 0]
      a[0], a[a[0]] = a[a[0]], a[0]
      dis(swap)

      swap()


      Output is



       4 0 LOAD_CONST 1 (1)
      2 LOAD_CONST 2 (0)
      4 BUILD_LIST 2
      6 STORE_FAST 0 (a)

      5 8 LOAD_FAST 0 (a)
      10 LOAD_FAST 0 (a)
      12 LOAD_CONST 2 (0)
      14 BINARY_SUBSCR
      16 BINARY_SUBSCR
      18 LOAD_FAST 0 (a)
      20 LOAD_CONST 2 (0)
      22 BINARY_SUBSCR
      24 ROT_TWO
      26 LOAD_FAST 0 (a)
      28 LOAD_CONST 2 (0)
      30 STORE_SUBSCR
      32 LOAD_FAST 0 (a)
      34 LOAD_FAST 0 (a)
      36 LOAD_CONST 2 (0)
      38 BINARY_SUBSCR
      40 STORE_SUBSCR
      42 LOAD_CONST 0 (None)
      44 RETURN_VALUE


      You can see the output byte code that top two items are the same. Hence it doesn't swap







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Aug 21 at 14:30

























      answered Aug 21 at 13:59









      argo

      2,1231725




      2,1231725











      • I think Swaps the two top-most stack items. is still not an implementation detail. How do these two items swap?
        – Sraw
        Aug 21 at 14:03











      • @Sraw check my updated explanation. I think it would make more sense now
        – argo
        Aug 21 at 14:23
















      • I think Swaps the two top-most stack items. is still not an implementation detail. How do these two items swap?
        – Sraw
        Aug 21 at 14:03











      • @Sraw check my updated explanation. I think it would make more sense now
        – argo
        Aug 21 at 14:23















      I think Swaps the two top-most stack items. is still not an implementation detail. How do these two items swap?
      – Sraw
      Aug 21 at 14:03





      I think Swaps the two top-most stack items. is still not an implementation detail. How do these two items swap?
      – Sraw
      Aug 21 at 14:03













      @Sraw check my updated explanation. I think it would make more sense now
      – argo
      Aug 21 at 14:23




      @Sraw check my updated explanation. I think it would make more sense now
      – argo
      Aug 21 at 14:23












      up vote
      7
      down vote













      This kind of the behaviour is indeed related to the way Python evaluates the expression of the type



      a,b=b,a


      In fact, what Python does is first it "prepares" the values of the right side by creating a tuple (b,a). Then this tuple is unpacked and assigned to the variables in the reverse order.



      It is important to note that the temporary tuple is created using values of variables (de facto copies of values), not references to the variables (you can read here about the difference between passing by value and by reference).



      To break down the example with reference types (lists) that you used:



      a = [2,1,0] 
      a[0], a[a[0]] = a[a[0]], a[0]



      1. a[a[0]] takes the value from the a[0] element (equal to 2) of the list a (value 0).


      2. a[0] is 2 hence the tuple created is (0,2)

      3. Tuple (0,2) is unpacked and 0 replaces 2 in the list (0th element).

      4. Now, a[a[0]] can be read as: take 0th element of list a (which is currently 0) and then replace the value in the list at that place with 2 from tuple unpacking (now 0 is replaced by 2 - which make the operation look like it does nothing to the list).

      As suggested in the answer from von Oak changing the order helps because the step from the point 4. above does not replace the value again.






      share|improve this answer
























        up vote
        7
        down vote













        This kind of the behaviour is indeed related to the way Python evaluates the expression of the type



        a,b=b,a


        In fact, what Python does is first it "prepares" the values of the right side by creating a tuple (b,a). Then this tuple is unpacked and assigned to the variables in the reverse order.



        It is important to note that the temporary tuple is created using values of variables (de facto copies of values), not references to the variables (you can read here about the difference between passing by value and by reference).



        To break down the example with reference types (lists) that you used:



        a = [2,1,0] 
        a[0], a[a[0]] = a[a[0]], a[0]



        1. a[a[0]] takes the value from the a[0] element (equal to 2) of the list a (value 0).


        2. a[0] is 2 hence the tuple created is (0,2)

        3. Tuple (0,2) is unpacked and 0 replaces 2 in the list (0th element).

        4. Now, a[a[0]] can be read as: take 0th element of list a (which is currently 0) and then replace the value in the list at that place with 2 from tuple unpacking (now 0 is replaced by 2 - which make the operation look like it does nothing to the list).

        As suggested in the answer from von Oak changing the order helps because the step from the point 4. above does not replace the value again.






        share|improve this answer






















          up vote
          7
          down vote










          up vote
          7
          down vote









          This kind of the behaviour is indeed related to the way Python evaluates the expression of the type



          a,b=b,a


          In fact, what Python does is first it "prepares" the values of the right side by creating a tuple (b,a). Then this tuple is unpacked and assigned to the variables in the reverse order.



          It is important to note that the temporary tuple is created using values of variables (de facto copies of values), not references to the variables (you can read here about the difference between passing by value and by reference).



          To break down the example with reference types (lists) that you used:



          a = [2,1,0] 
          a[0], a[a[0]] = a[a[0]], a[0]



          1. a[a[0]] takes the value from the a[0] element (equal to 2) of the list a (value 0).


          2. a[0] is 2 hence the tuple created is (0,2)

          3. Tuple (0,2) is unpacked and 0 replaces 2 in the list (0th element).

          4. Now, a[a[0]] can be read as: take 0th element of list a (which is currently 0) and then replace the value in the list at that place with 2 from tuple unpacking (now 0 is replaced by 2 - which make the operation look like it does nothing to the list).

          As suggested in the answer from von Oak changing the order helps because the step from the point 4. above does not replace the value again.






          share|improve this answer












          This kind of the behaviour is indeed related to the way Python evaluates the expression of the type



          a,b=b,a


          In fact, what Python does is first it "prepares" the values of the right side by creating a tuple (b,a). Then this tuple is unpacked and assigned to the variables in the reverse order.



          It is important to note that the temporary tuple is created using values of variables (de facto copies of values), not references to the variables (you can read here about the difference between passing by value and by reference).



          To break down the example with reference types (lists) that you used:



          a = [2,1,0] 
          a[0], a[a[0]] = a[a[0]], a[0]



          1. a[a[0]] takes the value from the a[0] element (equal to 2) of the list a (value 0).


          2. a[0] is 2 hence the tuple created is (0,2)

          3. Tuple (0,2) is unpacked and 0 replaces 2 in the list (0th element).

          4. Now, a[a[0]] can be read as: take 0th element of list a (which is currently 0) and then replace the value in the list at that place with 2 from tuple unpacking (now 0 is replaced by 2 - which make the operation look like it does nothing to the list).

          As suggested in the answer from von Oak changing the order helps because the step from the point 4. above does not replace the value again.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Aug 21 at 14:07









          sophros

          1,343416




          1,343416




















              up vote
              1
              down vote













              Python and C++ are different languages with different rules. That's largely the reason why superficially similar constructs behave differently in these languages.



              You cannot write a generic swap in Python that would work with input like a[0], a[a[0]]. This is not a problem. You shouldn't ever try to swap such things in any language in order to avoid confusion and improve your chances for future employment as a programmer.



              If you absolutely positively need to swap array elements indexed by elements of the same array, you can do it like so in Python:



              p, q, a[p], a[q] = index0, index1, a[q], a[p]


              where index0 and index1 may be any expression involving a[i], a[a[i]], a[a[a[i]]] or anything similar. For example



              p, q, a[p], a[q] = a[0], a[a[0]], a[q], a[p]


              works.






              share|improve this answer


























                up vote
                1
                down vote













                Python and C++ are different languages with different rules. That's largely the reason why superficially similar constructs behave differently in these languages.



                You cannot write a generic swap in Python that would work with input like a[0], a[a[0]]. This is not a problem. You shouldn't ever try to swap such things in any language in order to avoid confusion and improve your chances for future employment as a programmer.



                If you absolutely positively need to swap array elements indexed by elements of the same array, you can do it like so in Python:



                p, q, a[p], a[q] = index0, index1, a[q], a[p]


                where index0 and index1 may be any expression involving a[i], a[a[i]], a[a[a[i]]] or anything similar. For example



                p, q, a[p], a[q] = a[0], a[a[0]], a[q], a[p]


                works.






                share|improve this answer
























                  up vote
                  1
                  down vote










                  up vote
                  1
                  down vote









                  Python and C++ are different languages with different rules. That's largely the reason why superficially similar constructs behave differently in these languages.



                  You cannot write a generic swap in Python that would work with input like a[0], a[a[0]]. This is not a problem. You shouldn't ever try to swap such things in any language in order to avoid confusion and improve your chances for future employment as a programmer.



                  If you absolutely positively need to swap array elements indexed by elements of the same array, you can do it like so in Python:



                  p, q, a[p], a[q] = index0, index1, a[q], a[p]


                  where index0 and index1 may be any expression involving a[i], a[a[i]], a[a[a[i]]] or anything similar. For example



                  p, q, a[p], a[q] = a[0], a[a[0]], a[q], a[p]


                  works.






                  share|improve this answer














                  Python and C++ are different languages with different rules. That's largely the reason why superficially similar constructs behave differently in these languages.



                  You cannot write a generic swap in Python that would work with input like a[0], a[a[0]]. This is not a problem. You shouldn't ever try to swap such things in any language in order to avoid confusion and improve your chances for future employment as a programmer.



                  If you absolutely positively need to swap array elements indexed by elements of the same array, you can do it like so in Python:



                  p, q, a[p], a[q] = index0, index1, a[q], a[p]


                  where index0 and index1 may be any expression involving a[i], a[a[i]], a[a[a[i]]] or anything similar. For example



                  p, q, a[p], a[q] = a[0], a[a[0]], a[q], a[p]


                  works.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Aug 21 at 14:38

























                  answered Aug 21 at 13:59









                  n.m.

                  68.6k882165




                  68.6k882165




















                      up vote
                      0
                      down vote













                      It's easy to think about it also only on the paper (e.g. at the job interview) and you don't need to debug or disassemble code to bytecode for understanding.



                      I also think it hasn't anything to do with the implementation of swap function in C++. These are unrelated things.



                      What you only need to know is that the right side is completely evaluated first and then the values from the right side of the expression are assigned to the values on the left side in the order from the left to the right. Sophros answered it right way I only expand the idea further and in more detail.



                      Imagine the first case. We have:



                      a = [2,1,0]

                      a[0], a[a[0]] = a[a[0]], a[0]


                      When we start to execute this code, the right side evaluates first, so we will have



                      a[0], a[a[0]] = a[a[0]], a[0] # a[a[0]] == 0, a[0] == 2, a == [2, 1, 0]


                      On the right side, we have tuple (0, 2) and a is still [2, 1, 0]



                      Next, we start to assign to the left side of the expression from the left, so to the a[0] we assign the first item from the tuple, which is 0. Now we have



                      a[0], a[a[0]] = (0, 2) # a[0] == 0, a == [0, 1, 0]


                      And now we execute the last part of the assignment, which is to a[a[0]] assign 2. But a[0] is now 0, so after reduction we assign to a[0] value 2. Therefore values after the last assignment are



                      a[0], a[a[0]] = (0, 2) # a[a[0]] == 2, a == [2, 1, 0]


                      Which seems, that nothing changed and values didn't swap, but as is apparent from above a was [2,1,0], then [0,1,0] and lastly again [2,1,0]. So it seems, nothing changed and swap doesn't work.



                      And now the second case, where we only change the order of variables in the expression:



                      a = [2,1,0]

                      a[a[0]], a[0] = a[0], a[a[0]]


                      When we start to execute this code, the right side evaluates first, so we will have



                      a[a[0]], a[0] = a[0], a[a[0]] # a[0] == 2, a[a[0]] == 0, a == [2, 1, 0]


                      On the right side, we have tuple (2, 0) and a is still [2, 1, 0]



                      Next, we start to assign to the left side of the expression from the left, so to the a[a[0]] we assign the first item from the tuple, which is 2. a[0] is 2, so after reduction, we assign to a[2] value 2. Now we have



                      a[a[0]], a[0] = (2, 0) # a[a[0]] == 2, a == [2, 1, 2]


                      And now we execute the last part of the assignment, which is to a[0] assign 0. Therefore values after the last assignment are



                      a[a[0]], a[0] = (2, 0) # a[0] == 0, a == [0, 1, 2]


                      Now this works as expected.



                      So it is necessary also think about the order when you have dependent variables in your swap expression. As dependent variables I mean that in the first case we have on the left side a[0], a[a[0]] that means a[0] change it's value and a[a[0]] use this changed value, which leads to unwanted behavior.



                      Finally, regardless of the programming language, it's better not to use dependent variables (array index for another array index etc.), when you want to swap their values.






                      share|improve this answer






















                      • What about swapping a[a[a[0]]] and a[a[0]]? Would it work?
                        – n.m.
                        Aug 21 at 14:22










                      • I vastly extended my answer, so now you can try your example as the exercise:-)
                        – von Oak
                        Aug 21 at 23:30














                      up vote
                      0
                      down vote













                      It's easy to think about it also only on the paper (e.g. at the job interview) and you don't need to debug or disassemble code to bytecode for understanding.



                      I also think it hasn't anything to do with the implementation of swap function in C++. These are unrelated things.



                      What you only need to know is that the right side is completely evaluated first and then the values from the right side of the expression are assigned to the values on the left side in the order from the left to the right. Sophros answered it right way I only expand the idea further and in more detail.



                      Imagine the first case. We have:



                      a = [2,1,0]

                      a[0], a[a[0]] = a[a[0]], a[0]


                      When we start to execute this code, the right side evaluates first, so we will have



                      a[0], a[a[0]] = a[a[0]], a[0] # a[a[0]] == 0, a[0] == 2, a == [2, 1, 0]


                      On the right side, we have tuple (0, 2) and a is still [2, 1, 0]



                      Next, we start to assign to the left side of the expression from the left, so to the a[0] we assign the first item from the tuple, which is 0. Now we have



                      a[0], a[a[0]] = (0, 2) # a[0] == 0, a == [0, 1, 0]


                      And now we execute the last part of the assignment, which is to a[a[0]] assign 2. But a[0] is now 0, so after reduction we assign to a[0] value 2. Therefore values after the last assignment are



                      a[0], a[a[0]] = (0, 2) # a[a[0]] == 2, a == [2, 1, 0]


                      Which seems, that nothing changed and values didn't swap, but as is apparent from above a was [2,1,0], then [0,1,0] and lastly again [2,1,0]. So it seems, nothing changed and swap doesn't work.



                      And now the second case, where we only change the order of variables in the expression:



                      a = [2,1,0]

                      a[a[0]], a[0] = a[0], a[a[0]]


                      When we start to execute this code, the right side evaluates first, so we will have



                      a[a[0]], a[0] = a[0], a[a[0]] # a[0] == 2, a[a[0]] == 0, a == [2, 1, 0]


                      On the right side, we have tuple (2, 0) and a is still [2, 1, 0]



                      Next, we start to assign to the left side of the expression from the left, so to the a[a[0]] we assign the first item from the tuple, which is 2. a[0] is 2, so after reduction, we assign to a[2] value 2. Now we have



                      a[a[0]], a[0] = (2, 0) # a[a[0]] == 2, a == [2, 1, 2]


                      And now we execute the last part of the assignment, which is to a[0] assign 0. Therefore values after the last assignment are



                      a[a[0]], a[0] = (2, 0) # a[0] == 0, a == [0, 1, 2]


                      Now this works as expected.



                      So it is necessary also think about the order when you have dependent variables in your swap expression. As dependent variables I mean that in the first case we have on the left side a[0], a[a[0]] that means a[0] change it's value and a[a[0]] use this changed value, which leads to unwanted behavior.



                      Finally, regardless of the programming language, it's better not to use dependent variables (array index for another array index etc.), when you want to swap their values.






                      share|improve this answer






















                      • What about swapping a[a[a[0]]] and a[a[0]]? Would it work?
                        – n.m.
                        Aug 21 at 14:22










                      • I vastly extended my answer, so now you can try your example as the exercise:-)
                        – von Oak
                        Aug 21 at 23:30












                      up vote
                      0
                      down vote










                      up vote
                      0
                      down vote









                      It's easy to think about it also only on the paper (e.g. at the job interview) and you don't need to debug or disassemble code to bytecode for understanding.



                      I also think it hasn't anything to do with the implementation of swap function in C++. These are unrelated things.



                      What you only need to know is that the right side is completely evaluated first and then the values from the right side of the expression are assigned to the values on the left side in the order from the left to the right. Sophros answered it right way I only expand the idea further and in more detail.



                      Imagine the first case. We have:



                      a = [2,1,0]

                      a[0], a[a[0]] = a[a[0]], a[0]


                      When we start to execute this code, the right side evaluates first, so we will have



                      a[0], a[a[0]] = a[a[0]], a[0] # a[a[0]] == 0, a[0] == 2, a == [2, 1, 0]


                      On the right side, we have tuple (0, 2) and a is still [2, 1, 0]



                      Next, we start to assign to the left side of the expression from the left, so to the a[0] we assign the first item from the tuple, which is 0. Now we have



                      a[0], a[a[0]] = (0, 2) # a[0] == 0, a == [0, 1, 0]


                      And now we execute the last part of the assignment, which is to a[a[0]] assign 2. But a[0] is now 0, so after reduction we assign to a[0] value 2. Therefore values after the last assignment are



                      a[0], a[a[0]] = (0, 2) # a[a[0]] == 2, a == [2, 1, 0]


                      Which seems, that nothing changed and values didn't swap, but as is apparent from above a was [2,1,0], then [0,1,0] and lastly again [2,1,0]. So it seems, nothing changed and swap doesn't work.



                      And now the second case, where we only change the order of variables in the expression:



                      a = [2,1,0]

                      a[a[0]], a[0] = a[0], a[a[0]]


                      When we start to execute this code, the right side evaluates first, so we will have



                      a[a[0]], a[0] = a[0], a[a[0]] # a[0] == 2, a[a[0]] == 0, a == [2, 1, 0]


                      On the right side, we have tuple (2, 0) and a is still [2, 1, 0]



                      Next, we start to assign to the left side of the expression from the left, so to the a[a[0]] we assign the first item from the tuple, which is 2. a[0] is 2, so after reduction, we assign to a[2] value 2. Now we have



                      a[a[0]], a[0] = (2, 0) # a[a[0]] == 2, a == [2, 1, 2]


                      And now we execute the last part of the assignment, which is to a[0] assign 0. Therefore values after the last assignment are



                      a[a[0]], a[0] = (2, 0) # a[0] == 0, a == [0, 1, 2]


                      Now this works as expected.



                      So it is necessary also think about the order when you have dependent variables in your swap expression. As dependent variables I mean that in the first case we have on the left side a[0], a[a[0]] that means a[0] change it's value and a[a[0]] use this changed value, which leads to unwanted behavior.



                      Finally, regardless of the programming language, it's better not to use dependent variables (array index for another array index etc.), when you want to swap their values.






                      share|improve this answer














                      It's easy to think about it also only on the paper (e.g. at the job interview) and you don't need to debug or disassemble code to bytecode for understanding.



                      I also think it hasn't anything to do with the implementation of swap function in C++. These are unrelated things.



                      What you only need to know is that the right side is completely evaluated first and then the values from the right side of the expression are assigned to the values on the left side in the order from the left to the right. Sophros answered it right way I only expand the idea further and in more detail.



                      Imagine the first case. We have:



                      a = [2,1,0]

                      a[0], a[a[0]] = a[a[0]], a[0]


                      When we start to execute this code, the right side evaluates first, so we will have



                      a[0], a[a[0]] = a[a[0]], a[0] # a[a[0]] == 0, a[0] == 2, a == [2, 1, 0]


                      On the right side, we have tuple (0, 2) and a is still [2, 1, 0]



                      Next, we start to assign to the left side of the expression from the left, so to the a[0] we assign the first item from the tuple, which is 0. Now we have



                      a[0], a[a[0]] = (0, 2) # a[0] == 0, a == [0, 1, 0]


                      And now we execute the last part of the assignment, which is to a[a[0]] assign 2. But a[0] is now 0, so after reduction we assign to a[0] value 2. Therefore values after the last assignment are



                      a[0], a[a[0]] = (0, 2) # a[a[0]] == 2, a == [2, 1, 0]


                      Which seems, that nothing changed and values didn't swap, but as is apparent from above a was [2,1,0], then [0,1,0] and lastly again [2,1,0]. So it seems, nothing changed and swap doesn't work.



                      And now the second case, where we only change the order of variables in the expression:



                      a = [2,1,0]

                      a[a[0]], a[0] = a[0], a[a[0]]


                      When we start to execute this code, the right side evaluates first, so we will have



                      a[a[0]], a[0] = a[0], a[a[0]] # a[0] == 2, a[a[0]] == 0, a == [2, 1, 0]


                      On the right side, we have tuple (2, 0) and a is still [2, 1, 0]



                      Next, we start to assign to the left side of the expression from the left, so to the a[a[0]] we assign the first item from the tuple, which is 2. a[0] is 2, so after reduction, we assign to a[2] value 2. Now we have



                      a[a[0]], a[0] = (2, 0) # a[a[0]] == 2, a == [2, 1, 2]


                      And now we execute the last part of the assignment, which is to a[0] assign 0. Therefore values after the last assignment are



                      a[a[0]], a[0] = (2, 0) # a[0] == 0, a == [0, 1, 2]


                      Now this works as expected.



                      So it is necessary also think about the order when you have dependent variables in your swap expression. As dependent variables I mean that in the first case we have on the left side a[0], a[a[0]] that means a[0] change it's value and a[a[0]] use this changed value, which leads to unwanted behavior.



                      Finally, regardless of the programming language, it's better not to use dependent variables (array index for another array index etc.), when you want to swap their values.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Aug 21 at 23:36

























                      answered Aug 21 at 13:53









                      von Oak

                      753313




                      753313











                      • What about swapping a[a[a[0]]] and a[a[0]]? Would it work?
                        – n.m.
                        Aug 21 at 14:22










                      • I vastly extended my answer, so now you can try your example as the exercise:-)
                        – von Oak
                        Aug 21 at 23:30
















                      • What about swapping a[a[a[0]]] and a[a[0]]? Would it work?
                        – n.m.
                        Aug 21 at 14:22










                      • I vastly extended my answer, so now you can try your example as the exercise:-)
                        – von Oak
                        Aug 21 at 23:30















                      What about swapping a[a[a[0]]] and a[a[0]]? Would it work?
                      – n.m.
                      Aug 21 at 14:22




                      What about swapping a[a[a[0]]] and a[a[0]]? Would it work?
                      – n.m.
                      Aug 21 at 14:22












                      I vastly extended my answer, so now you can try your example as the exercise:-)
                      – von Oak
                      Aug 21 at 23:30




                      I vastly extended my answer, so now you can try your example as the exercise:-)
                      – von Oak
                      Aug 21 at 23:30

















                       

                      draft saved


                      draft discarded















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51950193%2fpython-a-b-b-a-implementation-how-is-it-different-from-c-swap-function%23new-answer', 'question_page');

                      );

                      Post as a guest













































































                      Popular posts from this blog

                      How to check contact read email or not when send email to Individual?

                      Bahrain

                      Postfix configuration issue with fips on centos 7; mailgun relay