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.
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.
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.
The assignment list expressions are evaluated left-to-right while assigning.
Here is what happens:
(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]
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With