【问题标题】:Why is my code to swap two elements of a list going wrong?为什么我交换列表中两个元素的代码出错了?
【发布时间】:2019-03-01 05:42:20
【问题描述】:

这是我的代码:

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]。
  • 对不起,我弄错了,[2, 2, 1, 4, 5] 是真的。
  • 另外提一下,你所期待的。

标签: python python-3.x swap iterable-unpacking


【解决方案1】:

这项任务做得很多。让我们分解一切……

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]

【讨论】:

    【解决方案2】:

    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

    【讨论】:

      猜你喜欢
      • 2017-07-16
      • 1970-01-01
      • 2022-01-23
      • 2020-11-23
      • 2011-09-02
      • 1970-01-01
      • 2021-05-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多