这是我的代码:
a = [1, 2, 3, 4, 5]
a[0], a[a[0]] = a[a[0]], a[0]
print(a)
我正在尝试将a[0]
与a[a[0]]
交换(在这种情况下,即a[1]
),所以我期望的结果是:
[2, 1, 3, 4, 5]
我得到的结果是[2, 2, 1, 4, 5]
,这不是我想要的。
如果我将a[0], a[a[0]] = a[a[0]], a[0]
简化为a[0], a[1] = a[1], a[0]
,就可以了。
如何使列表内的交换像a, b = b, a
一样工作?
答案 0 :(得分:2)
这项工作做得很多。让我们分解一切……
a = [1, 2, 3, 4, 5]
好吧,这很容易。下一个:
a[0], a[a[0]] = a[a[0]], a[0]
在任何分配中发生的第一件事是评估右侧,因此:
a[a[0]], a[0]
减少为a[1], a[0]
,其结果为(2, 1)
。
然后,每个分配目标又从分配给它的右侧获得这些项目之一:
a[0] = 2 # 2 == first item in the (already evaluated) right hand side
现在完成了,a
看起来像这样:
[2, 2, 3, 4, 5]
现在,我们将执行第二个任务:
a[a[0]] = 1 # 1 == second item in the (already evaluated) right hand side
但是等等! a[0]
现在为2
,因此减少为
a[2] = 1
而且,瞧,如果我们再次看a
,它的结局为:
[2, 2, 1, 4, 5]
您发现的是,尽管Python声称能够同时交换两个值,例如a, b = b, a
,这不是真的。实际上,它几乎总是可行,但是如果其中一个值是另一个描述的一部分(在这种情况下,a[0]
是a[a[0]]
的描述的一部分),则实现细节可能会绊倒您上。
解决此问题的方法是在开始重新分配内容之前存储a[0]
的初始值:
a = [1, 2, 3, 4, 5]
tmp = a[0]
a[0], a[tmp] = a[tmp], a[0]
之后,a
会符合您的期望:
[2, 1, 3, 4, 5]
答案 1 :(得分:0)
python系统lib dis
模块可能会有所帮助。 dis
模块通过分解来支持CPython字节码的分析。您可以对其进行分解,以查看交换在内部如何工作。
In [1]: import dis
In [2]: def func():
...: a = [1, 2, 3, 4, 5]
...: a[0], a[a[0]] = a[a[0]], a[0]
...: print a
In [3]: func()
[2, 2, 1, 4, 5]
In [4]: dis.dis(func)
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 BUILD_LIST 5
18 STORE_FAST 0 (a) # make list: a = [1, 2, 3, 4, 5]
3 21 LOAD_FAST 0 (a) # stack: a
24 LOAD_FAST 0 (a) # stack: a|a
27 LOAD_CONST 6 (0) # stack: a|a|0
30 BINARY_SUBSCR # stack: a|1
31 BINARY_SUBSCR # stack: 2
32 LOAD_FAST 0 (a) # stack: 2|a
35 LOAD_CONST 6 (0) # stack: 2|a|0
38 BINARY_SUBSCR # stack: 2|1
39 ROT_TWO # stack: 1|2
40 LOAD_FAST 0 (a) # stack: 1|2|a
43 LOAD_CONST 6 (0) # stack: 1|2|a|0
46 STORE_SUBSCR # stack: 1| a: a[0] = 2
47 LOAD_FAST 0 (a) # stack: 1|a
50 LOAD_FAST 0 (a) # stack: 1|a|a
53 LOAD_CONST 6 (0) # stack: 1|a|a|0
56 BINARY_SUBSCR # stack: 1|a|2
57 STORE_SUBSCR # stack: a: a[2] = 1
4 58 LOAD_FAST 0 (a)
61 PRINT_ITEM
62 PRINT_NEWLINE
63 LOAD_CONST 0 (None)
66 RETURN_VALUE