为什么我不能在一行中交换列表中的两个项目?
Why can't I swap two items in a list in one line?
为什么这不起作用(不交换值):
lol = ["test","test2"]
lol[lol.index("test")], lol[lol.index("test2")] = lol[lol.index("test2")], lol[lol.index("test")]
但这行得通(交换了值):
i1 = lol.index("test")
i2 = lol.index("test2")
lol[i1], lol[i2] = lol[i2], lol[i1]
第一个例子不起作用的原因是因为你多次调用.index()
,每次之后,列表中的值都在变化,所以代码中找到的索引不具有代表性元素的实际位置。第二个示例有效,因为您将第一个索引存储在两个变量中,并在交换中使用它们。
第一个示例概述:
lol[lol.index("test")], lol[lol.index("test2")] = lol[lol.index("test2")], lol[lol.index("test")]
第一部分:lol[lol.index("test")]
存储 0
第二部分:lol[lol.index("test2")]
存储 1
第三部分:lol[lol.index("test2")]
仍然存储1
这就是它变得有趣的时候。示例的第四部分 lol[lol.index("test")]
找到 test
的索引,但是,test
是从代码的第三段分配给 1
的。因此,lol[lol.index("test")]
是 1
,而不是 0
。因此,lol[lol.index("test2")]
仍然存储 1
.
因为 X,Y="test","test2"
将被处理为 X="test";Y="test2"
lol = ["test","test2"]
lol[lol.index("test")], lol[lol.index("test2")] = lol[lol.index("test2")], lol[lol.index("test")]
首先对右手边求值,所以你得到:
lol[lol.index("test")], lol[lol.index("test2")] = "test2", "test"
这将与以下行具有相同的效果:
lol[lol.index("test")]="test2"
# returns 0
# lol==["test2","test2"]
lol[lol.index("test2")]="test"
# returns 0
说明
归结为正确理解 evaluation order 在这里的工作原理,特别是 expr3, expr4 = expr1, expr2
.
的情况
如果我们单步执行语句 lol[lol.index("test")], lol[lol.index("test2")] = lol[lol.index("test2")], lol[lol.index("test")]
,我们会得到如下结果:
r1=evaluate(expr1) --> "test2"
r2=evaluate(expr2) --> "test"
evaluate(expr3)=r1 --> lol[0] = "test2" --> lol = ["test2","test2"]
evaluate(expr4)=r2 --> lol[0] = "test" --> lol = ["test", "test2"]
另一个片段很简单:
i1 = lol.index("test")
i2 = lol.index("test2")
lol[i1], lol[i2] = lol[i2], lol[i1]
it1) i1 = 0
it2) i2 = 1
it3) lol[i1], lol[i2] = "test2", lol[i1]
it4) lol[i1], lol[i2] = "test2", "test"
it5) lol[i1] = "test2"
it6) lol[i2] = "test"
Oneliner 替代方案
像这些应该做的事情:
lol = lol[lol.index("test2")], lol[lol.index("test")]
lol[0], lol[1] = lol[1], lol[0]
lol[0], lol[1] = lol[lol.index("test2")], lol[lol.index("test")]
补充说明
如果你真的想知道更多关于这些函数是如何解释的,一个很好的方法是使用模块 dis,例如:
>>> import dis
>>> def f():
... lst[lst.index(str1)], lst[lst.index(str2)] = lst[lst.index(str2)], lst[lst.index(str1)]
...
>>> dis.dis(f)
2 0 LOAD_GLOBAL 0 (lst)
3 LOAD_GLOBAL 0 (lst)
6 LOAD_ATTR 1 (index)
9 LOAD_GLOBAL 2 (str2)
12 CALL_FUNCTION 1
15 BINARY_SUBSCR
16 LOAD_GLOBAL 0 (lst)
19 LOAD_GLOBAL 0 (lst)
22 LOAD_ATTR 1 (index)
25 LOAD_GLOBAL 3 (str1)
28 CALL_FUNCTION 1
31 BINARY_SUBSCR
32 ROT_TWO
33 LOAD_GLOBAL 0 (lst)
36 LOAD_GLOBAL 0 (lst)
39 LOAD_ATTR 1 (index)
42 LOAD_GLOBAL 3 (str1)
45 CALL_FUNCTION 1
48 STORE_SUBSCR
49 LOAD_GLOBAL 0 (lst)
52 LOAD_GLOBAL 0 (lst)
55 LOAD_ATTR 1 (index)
58 LOAD_GLOBAL 2 (str2)
61 CALL_FUNCTION 1
64 STORE_SUBSCR
65 LOAD_CONST 0 (None)
68 RETURN_VALUE
>>>
为什么这不起作用(不交换值):
lol = ["test","test2"]
lol[lol.index("test")], lol[lol.index("test2")] = lol[lol.index("test2")], lol[lol.index("test")]
但这行得通(交换了值):
i1 = lol.index("test")
i2 = lol.index("test2")
lol[i1], lol[i2] = lol[i2], lol[i1]
第一个例子不起作用的原因是因为你多次调用.index()
,每次之后,列表中的值都在变化,所以代码中找到的索引不具有代表性元素的实际位置。第二个示例有效,因为您将第一个索引存储在两个变量中,并在交换中使用它们。
第一个示例概述:
lol[lol.index("test")], lol[lol.index("test2")] = lol[lol.index("test2")], lol[lol.index("test")]
第一部分:lol[lol.index("test")]
存储 0
第二部分:lol[lol.index("test2")]
存储 1
第三部分:lol[lol.index("test2")]
仍然存储1
这就是它变得有趣的时候。示例的第四部分 lol[lol.index("test")]
找到 test
的索引,但是,test
是从代码的第三段分配给 1
的。因此,lol[lol.index("test")]
是 1
,而不是 0
。因此,lol[lol.index("test2")]
仍然存储 1
.
因为 X,Y="test","test2"
将被处理为 X="test";Y="test2"
lol = ["test","test2"]
lol[lol.index("test")], lol[lol.index("test2")] = lol[lol.index("test2")], lol[lol.index("test")]
首先对右手边求值,所以你得到:
lol[lol.index("test")], lol[lol.index("test2")] = "test2", "test"
这将与以下行具有相同的效果:
lol[lol.index("test")]="test2"
# returns 0
# lol==["test2","test2"]
lol[lol.index("test2")]="test"
# returns 0
说明
归结为正确理解 evaluation order 在这里的工作原理,特别是 expr3, expr4 = expr1, expr2
.
如果我们单步执行语句 lol[lol.index("test")], lol[lol.index("test2")] = lol[lol.index("test2")], lol[lol.index("test")]
,我们会得到如下结果:
r1=evaluate(expr1) --> "test2"
r2=evaluate(expr2) --> "test"
evaluate(expr3)=r1 --> lol[0] = "test2" --> lol = ["test2","test2"]
evaluate(expr4)=r2 --> lol[0] = "test" --> lol = ["test", "test2"]
另一个片段很简单:
i1 = lol.index("test")
i2 = lol.index("test2")
lol[i1], lol[i2] = lol[i2], lol[i1]
it1) i1 = 0
it2) i2 = 1
it3) lol[i1], lol[i2] = "test2", lol[i1]
it4) lol[i1], lol[i2] = "test2", "test"
it5) lol[i1] = "test2"
it6) lol[i2] = "test"
Oneliner 替代方案
像这些应该做的事情:
lol = lol[lol.index("test2")], lol[lol.index("test")]
lol[0], lol[1] = lol[1], lol[0]
lol[0], lol[1] = lol[lol.index("test2")], lol[lol.index("test")]
补充说明
如果你真的想知道更多关于这些函数是如何解释的,一个很好的方法是使用模块 dis,例如:
>>> import dis
>>> def f():
... lst[lst.index(str1)], lst[lst.index(str2)] = lst[lst.index(str2)], lst[lst.index(str1)]
...
>>> dis.dis(f)
2 0 LOAD_GLOBAL 0 (lst)
3 LOAD_GLOBAL 0 (lst)
6 LOAD_ATTR 1 (index)
9 LOAD_GLOBAL 2 (str2)
12 CALL_FUNCTION 1
15 BINARY_SUBSCR
16 LOAD_GLOBAL 0 (lst)
19 LOAD_GLOBAL 0 (lst)
22 LOAD_ATTR 1 (index)
25 LOAD_GLOBAL 3 (str1)
28 CALL_FUNCTION 1
31 BINARY_SUBSCR
32 ROT_TWO
33 LOAD_GLOBAL 0 (lst)
36 LOAD_GLOBAL 0 (lst)
39 LOAD_ATTR 1 (index)
42 LOAD_GLOBAL 3 (str1)
45 CALL_FUNCTION 1
48 STORE_SUBSCR
49 LOAD_GLOBAL 0 (lst)
52 LOAD_GLOBAL 0 (lst)
55 LOAD_ATTR 1 (index)
58 LOAD_GLOBAL 2 (str2)
61 CALL_FUNCTION 1
64 STORE_SUBSCR
65 LOAD_CONST 0 (None)
68 RETURN_VALUE
>>>