python - 再次使用该值作为索引以避免局部变量时列表交换两个元素失败

标签 python list swap

l1=[0,2,1]
index=1
from ipdb import set_trace; set_trace()
l1[index], l1[l1[index]] = l1[l1[index]], l1[index]
print(l1)

为什么l1会相同? l1[1]l1[2] 不会交换。

最佳答案

您可以更改顺序,它会起作用:

l1=[0,2,1]
index=1
l1[l1[index]], l1[index] = l1[index], l1[l1[index]]
print(l1)

输出:

[0, 1, 2]

所以让我们首先看看代码的反汇编:

import dis
def switch():
    l1=[0,2,1]
    index=1
    l1[index], l1[l1[index]] = l1[l1[index]], l1[index]
    return l1
dis.dis(switch)
  2           0 LOAD_CONST               1 (0)
              2 LOAD_CONST               2 (2)
              4 LOAD_CONST               3 (1)
              6 BUILD_LIST               3
              8 STORE_FAST               0 (l1)

  3          10 LOAD_CONST               3 (1)
             12 STORE_FAST               1 (index)

  5          14 LOAD_FAST                0 (l1)
             16 LOAD_FAST                0 (l1)
             18 LOAD_FAST                1 (index)
             20 BINARY_SUBSCR
             22 BINARY_SUBSCR
             24 LOAD_FAST                0 (l1)
             26 LOAD_FAST                1 (index)
             28 BINARY_SUBSCR
             30 ROT_TWO
             32 LOAD_FAST                0 (l1)
             34 LOAD_FAST                1 (index)
             36 STORE_SUBSCR
             38 LOAD_FAST                0 (l1)
             40 LOAD_FAST                0 (l1)
             42 LOAD_FAST                1 (index)
             44 BINARY_SUBSCR
             46 STORE_SUBSCR

  6          48 LOAD_FAST                0 (l1)
             50 RETURN_VALUE

在这种类型的赋值中,首先计算表达式的右侧(请参阅 Evaluation Order )。因此,首先,指令集 (14 - 18) 加载 l1[index],即 1,并将其压入堆栈。然后,24-26加载l1[l1[index]],即2并将其压入堆栈。所以堆栈现在保存[2,1]ROT_TWO(30)交换堆栈并使其成为我们想要的顺序[1, 2]

现在,在 32 - 36 中,堆栈顶部,即 1 被分配给 l1[index],所以现在,l1[index] == 1,即l1[1] = 1

然后38 - 42,堆栈中剩余的元素,即2被弹出到l1[l1[index]],但现在是l1的值[index] 为 1,因此您实际上是在执行 l1[1] = 1。那么让我们看看:

l1[index], l1[l1[index]] = l1[l1[index]], l1[index]

loaded == 2, 1
after stack swapping == 1, 2

l1[1] == 1
l1[1] == 2
 # So you have modified only index 1, and then overwritten it with its original value.

类似这样的事情:

             14 LOAD_FAST                0 (l1)           ¯¯|
             16 LOAD_FAST                0 (l1)   ¯¯|  2    | 1 ---------->
             18 LOAD_FAST                1 (index)__|     __|              ↓
             20 BINARY_SUBSCR                                              |
             22 BINARY_SUBSCR                                              |
             24 LOAD_FAST                0 (l1)   ¯¯|  2 ------------------------>
             26 LOAD_FAST                1 (index)__|                      |       ↓
             28 BINARY_SUBSCR                                              |       |
             30 ROT_TWO                                                    |       |
             32 LOAD_FAST                0 (l1)   ¯¯|                      ↓       |
             34 LOAD_FAST                1 (index)__|  l1[1] = 1  <--------        |
             36 STORE_SUBSCR                                   |                   |
             38 LOAD_FAST                0 (l1)                |  ¯¯|              |
             40 LOAD_FAST                0 (l1)   ¯¯|          ↓    |              |
             42 LOAD_FAST                1 (index)__| l1[1] == 1  __| l1[1] = 2 <---
             44 BINARY_SUBSCR
             46 STORE_SUBSCR

如果我们在我的解决方案中遵循相同的推理:

l1[l1[index]], l1[index] = l1[index], l1[l1[index]]

loaded = 1, 2
after stack swapping == 2, 1

l1[2] = 2
l1[1] = 1
# Here, as you have not changed the value of `l1[index]` in the first assignment, the order remains.

现在您可以对 l1 = [0, 1, 2] 遵循相同的逻辑。虽然不需要解释,因为 l1[index]l1[l1[index]] 是相同的:

l1 = [0, 1, 2]

l1[index], l1[l1[index]] = l1[l1[index]], l1[index]

loaded = 1, 1
after stack swapping == 1, 1

l1[1] == 1
l1[1] == 1
------------------------------------------------------------------
l1[l1[index]], l1[index] = l1[index], l1[l1[index]]

loaded = 1, 1
after stack swapping == 1, 1

l1[1] = 1
l1[1] = 1
# Here both have same value, so it does not modify.

因此,当您通过传递列表元素作为索引来访问索引时,最好避免这种分配。相反,是 Explicit :

l1 = [0, 2, 1]
index1 = 1
index2 = l1[index1]
l1[index1], l1[index2] = l1[index2], l1[index1]
print(l1)
# [0, 1, 2]

关于python - 再次使用该值作为索引以避免局部变量时列表交换两个元素失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59729342/

相关文章:

python - Pydrive 后端不适用于口是心非——python

python - numpy.mean(X,axis=0) 当二维数组时,否则什么都不做

python - 如何将列表转换为查询集 Django

交换两个变量的javascript函数

java - 通过多态交换对象的位置

Python:如何使用 Python 访问 mp3 文件的元数据?

c# - 使用条件从另一个列表中删除列表项

jquery 可排序列表,具有动态生成的列表 ID

css - 仅通过 CSS 更改悬停内容

python - 根据两个不同大小的数据帧更新列并更新第一个数据帧中的值。 (python中vlookup的概念)