7

我在 python IDLE 中尝试了以下代码。但我似乎没有发现交换的元素。

>>> 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)]

根据代码,它应该颠倒2和4的位置。如果我错了,请纠正我。

4

3 回答 3

12

赋值列表表达式在赋值时从左到右求值。

这是发生的事情:

  • 右边的表达式被评估为产生(4, 2)
  • a[a.index(2)]被评估分配4给,a[2]被改变,列表变为[1, 4, 3, 4, 5, 6, 7]
  • a[a.index(4)]被评估分配2给,再次a[2]改变,因为现在第一个位置又回到了。4[1, 2, 3, 4, 5, 6, 7]

你可以在反汇编的 Python 字节码中看到这一点:

>>> 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        

通过指令索引 59,Python 计算了右侧表达式;接下来是作业。您可以看到a.index(2)(63-72) 首先被评估,然后STORE_SUBSCR存储,然后4才被评估(指令 79-85)。 a.index(4)

解决方法是为每个值调用.index() 一次,并将索引存储在变量中:

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]
于 2013-06-15T15:59:03.697 回答
5

Martijn 的回答很完整,并解释了您遇到的问题。如果您仍然想知道如何编写代码来满足您的需求,请尝试以下操作:

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

这里的想法基本上只是将index返回值存储在 List 本身之外的东西中。像这样单独保存索引可以避免您遇到的竞争条件。

于 2013-06-15T16:06:23.650 回答
1

为避免这种情况,您可以将.index()调用的结果存储在变量中,然后与它们进行交换:

>>> 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]

这样,您还可以避免在一次就足够的情况下调用该方法三次。

于 2013-06-15T16:05:56.947 回答