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

问题描述 投票:4回答:2

这是我的代码:

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之类的列表中进行此交换呢?

python python-3.x swap iterable-unpacking
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]

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

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

© www.soinside.com 2019 - 2024. All rights reserved.