为什么我的交换列表两个元素的代码出错了?

5

这是我的代码:

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]; print(a)在我的系统中,它打印出 [2, 2, 1, 4, 5]。 - taurus05
抱歉,我犯了一个错误,[2, 2, 1, 4, 5] 是正确的。 - zychyz
2
还要注明您期望得到什么。 - taurus05
2个回答

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]

Python声称在哪里? - Kelly Bundy

0

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

https://docs.python.org/3/library/dis.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接