在 Python 中同时分配索引不同的列表元素

Sop*_*hin 14 python variable-assignment

>>arr = [4, 2, 1, 3]
>>arr[0], arr[arr[0]-1] = arr[arr[0]-1], arr[0]
>>arr
Run Code Online (Sandbox Code Playgroud)

我期待的结果 >>[3, 2, 1, 4]

结果我得到 >>[3, 2, 4, 3]

基本上我试图交换 #4 和 #3(在我的实际问题中,索引不会是 0,而是一个迭代器 "i" 。所以我不能只做 arr[0], arr[3] = arr[ 3], arr[0]) 我认为我对同时分配的理解相当好。显然我错了。我不明白为什么赋值左侧的 arr[arr[0]-1] 计算的是 arr[2] 而不是 arr[3]。如果分配同时发生(从右侧评估),

arr[0](在左侧第二个元素的索引内​​)仍应为“4”

arr[0] -1(左侧第二个元素的索引)因此应为“3”

jua*_*aga 10

因为目标列表不会同时得到评估。这是文档的相关部分:

该对象必须是具有与目标列表中的目标相同数量的项目的可迭代对象,并且项目从左到右分配给相应的目标。

要记住两件事,右侧首先评估表达式。所以在 RHS 上,我们首先创建元组:

 (3, 4)
Run Code Online (Sandbox Code Playgroud)

请注意,这是从左到右完成的。现在,对左侧目标列表中的每个目标的分配是按顺序完成的:

arr[0] = 3
Run Code Online (Sandbox Code Playgroud)

那么下一个目标arr[0]3,而 3-1 是 2

arr[2] = 4
Run Code Online (Sandbox Code Playgroud)

所以一个简单的解决方案是在交换之前先计算索引:

>>> arr = [4, 2, 1, 3]
>>> i, j = arr[0] - 1, 0
>>> arr[j], arr[i] = arr[i], arr[j]
>>> arr
[3, 2, 1, 4]
Run Code Online (Sandbox Code Playgroud)

这是使用我们可以轻松定义的详细列表的演示:

>>> class NoisyList(list):
...     def __getitem__(self, item):
...         value = super().__getitem__(item)
...         print("GETTING", item, "value of", value)
...         return value
...     def __setitem__(self, item, value):
...         print("SETTING", item, 'with', value)
...         super().__setitem__(item, value)
...
>>> arr = NoisyList([4, 2, 1, 3])
>>> arr[0], arr[arr[0]-1] = arr[arr[0]-1], arr[0]
GETTING 0 value of 4
GETTING 3 value of 3
GETTING 0 value of 4
SETTING 0 with 3
GETTING 0 value of 3
SETTING 2 with 4
Run Code Online (Sandbox Code Playgroud)