问题描述
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]