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.
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.
To avoid this, you can store the the result of the .index()
calls in variables, then do the swap with them:
>>> a = [1,2,3,4,5,6,7]
>>> i2 = a.index(2)
>>> i4 = a.index(4)
>>> if i2<i4:
... a[i2], a[i4] = a[i4], a[i2]
>>> a
[1, 4, 3, 2, 5, 6, 7]
That way you also avoid calling that method three times when once is enough.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.