我在 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, 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]
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 本身之外的东西中。像这样单独保存索引可以避免您遇到的竞争条件。
为避免这种情况,您可以将.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]
这样,您还可以避免在一次就足够的情况下调用该方法三次。