简体   繁体   中英

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.

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]

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM