Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use list[list.index('')] queries in python

I tried the following code in python IDLE. But I didn't seem to find the elements swapped.

>>> a = [1,2,3,4,5,6,7]
>>> if(a.index(2)<a.index(4)):
...     a[a.index(2)],a[a.index(4)] = a[a.index(4)],a[a.index(2)]

According to the code, It should reverse the positions of 2 and 4. Correct me If I am wrong.

like image 522
Silent Spy Avatar asked Jun 15 '13 15:06

Silent Spy


People also ask

What does [- 1 :] mean in Python?

Python also allows you to index from the end of the list using a negative number, where [-1] returns the last element. This is super-useful since it means you don't have to programmatically find out the length of the iterable in order to work with elements at the end of it.

How does list indexing work in Python?

Each item in the list has a value(color name) and an index(its position in the list). Python uses zero-based indexing. That means, the first element(value 'red') has an index 0, the second(value 'green') has index 1, and so on.


2 Answers

The assignment list expressions are evaluated left-to-right while assigning.

Here is what happens:

  • The right-hand-expression is evaluated to yield (4, 2)
  • a[a.index(2)] is evaluated to assign 4 to, a[2] is altered, the list becomes [1, 4, 3, 4, 5, 6, 7]
  • a[a.index(4)] is evaluated to assign 2 to, a[2] is altered again because that is now the first position 4 is back to [1, 2, 3, 4, 5, 6, 7].

You can see this in the disassembled Python byte code:

>>> def foo():
...     a = [1,2,3,4,5,6,7]
...     a[a.index(2)],a[a.index(4)] = a[a.index(4)],a[a.index(2)]
... 
>>> import dis
>>> dis.dis(foo)
  2           0 LOAD_CONST               1 (1)
              3 LOAD_CONST               2 (2)
              6 LOAD_CONST               3 (3)
              9 LOAD_CONST               4 (4)
             12 LOAD_CONST               5 (5)
             15 LOAD_CONST               6 (6)
             18 LOAD_CONST               7 (7)
             21 BUILD_LIST               7
             24 STORE_FAST               0 (a)

  3          27 LOAD_FAST                0 (a)
             30 LOAD_FAST                0 (a)
             33 LOAD_ATTR                0 (index)
             36 LOAD_CONST               4 (4)
             39 CALL_FUNCTION            1
             42 BINARY_SUBSCR       
             43 LOAD_FAST                0 (a)
             46 LOAD_FAST                0 (a)
             49 LOAD_ATTR                0 (index)
             52 LOAD_CONST               2 (2)
             55 CALL_FUNCTION            1
             58 BINARY_SUBSCR       
             59 ROT_TWO             
             60 LOAD_FAST                0 (a)
             63 LOAD_FAST                0 (a)
             66 LOAD_ATTR                0 (index)
             69 LOAD_CONST               2 (2)
             72 CALL_FUNCTION            1
             75 STORE_SUBSCR        
             76 LOAD_FAST                0 (a)
             79 LOAD_FAST                0 (a)
             82 LOAD_ATTR                0 (index)
             85 LOAD_CONST               4 (4)
             88 CALL_FUNCTION            1
             91 STORE_SUBSCR        
             92 LOAD_CONST               0 (None)
             95 RETURN_VALUE        

By instruction index 59, Python has evaluated the right-hand-side expression; next up are the assignments. You can see that a.index(2) (63-72) is evaluated first, then the STORE_SUBSCR stores the 4, and only then a.index(4) is evaluated (instructions 79-85).

The workaround is to call .index() once for each value, and storing the indices in variables:

index_two, index_four = a.index(2), a.index(4)
if index_two < index_four:
    a[index_two], a[index_four] = a[index_four], a[index_two]
like image 183
Martijn Pieters Avatar answered Nov 08 '22 21:11

Martijn Pieters


Martijn's answer is complete and explains the problem you're having. If you are still wondering how to write code that does what you want, try something like this:

if (a.index(2) < a.index(4)):
    x,y = a.index(4),a.index(2)
    a[x],a[y] = a[y],a[x]

The idea here is basically just to store the index return values in something outside the List itself. Saving the indices separately like this avoids the race-condition you were having.

like image 25
john_science Avatar answered Nov 08 '22 20:11

john_science