为什么我的交换列表的两个元素的代码出错了?
Why is my code to swap two elements of a list going wrong?
这是我的代码:
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
一样工作?
这项作业做得很多。让我们分解一切......
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]
python 系统库 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
这是我的代码:
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
一样工作?
这项作业做得很多。让我们分解一切......
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]
python 系统库 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