我认为两者是相同的。
nums = [1, 2, 0]
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
print nums # [2, 1, 0]
nums = [1, 2, 0]
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]
print nums # [2, 2, 1]
但结果不同。
为什么结果不一样?(为什么是第二个结果?)
我认为两者是相同的。
nums = [1, 2, 0]
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
print nums # [2, 1, 0]
nums = [1, 2, 0]
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]
print nums # [2, 2, 1]
但结果不同。
为什么结果不一样?(为什么是第二个结果?)
列表是可变的
列表的主要部分是列表是可变的。这意味着可以更改列表的值。这是您面临麻烦的原因之一。有关更多信息,请参阅文档
评估顺序
另一部分是在解包元组时,评估从左到右开始。有关更多信息,请参阅文档
当您执行a,b = c,d
和 的值时c
,d
首先存储。然后从左侧开始,a
先将 的值改为c
,再将 的值b
改为d
。
这里要注意的是,如果b
在更改 的值时对 的位置有任何副作用a
,则将d
其分配给受 的副作用影响的后者 。b
b
a
现在来解决你的问题
在第一种情况下,
nums = [1, 2, 0]
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
nums[0]
最初是1
并且nums[nums[0]]
是2
因为它的计算结果为nums[1]
。因此 1,2 现在存储到内存中。
现在元组拆包从左侧发生,所以
nums[nums[0]] = nums[1] = 1 # NO side Effect.
nums[0] = 2
因此print nums
将打印[2, 1, 0]
然而在这种情况下
nums = [1, 2, 0]
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]
nums[nums[0]], nums[0]
就像第一种情况一样,将 2,1 放入堆栈。
但是在左侧,即 nums[0], nums[nums[0]]
的更改nums[0]
具有副作用,因为它用作 中的索引nums[nums[0]]
。因此
nums[0] = 2
nums[nums[0]] = nums[2] = 1 # NOTE THAT nums[0] HAS CHANGED
nums[1]
在 value 处保持不变2
。因此print nums
将打印[2, 2, 1]
您可以定义一个类来跟踪该过程:
class MyList(list):
def __getitem__(self, key):
print('get ' + str(key))
return super(MyList, self).__getitem__(key)
def __setitem__(self, key, value):
print('set ' + str(key) + ', ' + str(value))
return super(MyList, self).__setitem__(key, value)
对于第一种方法:
nums = MyList([1, 2, 0])
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
输出是:
get 0
get 0
get 1
get 0
set 1, 1
set 0, 2
而第二种方法:
nums = MyList([1, 2, 0])
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]
输出是:
get 0
get 1
get 0
set 0, 2
get 0
set 2, 1
在这两种方法中,前三行与元组生成有关,而后三行与赋值有关。第一种方法的右侧元组是(1, 2)
,第二种方法是(2, 1)
。
在赋值阶段,第一个方法 get nums[0]
which is1
和 set nums[1] = 1
,然后nums[0] = 2
,第二个方法 assign nums[0] = 2
,然后 get nums[0]
which is 2
,最后 set nums[2] = 1
。
这是因为python分配优先级是从左到右的。所以在下面的代码中:
nums = [1, 2, 0]
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
它首先分配nums[0]
tonums[nums[0]]
手段nums[1]==1
,然后由于列表是可变对象,因此 nums 将是:
[1,1,0]
然后nums[nums[0]]
将被分配到nums[0]
哪个意思nums[0]==2
和:
nums = [2,1,0]
第二部分也是如此。
请注意,这里的重点是列表对象是可变的,当您在一段代码中更改它时,它可以就地更改。因此它将影响其余代码。
Python 从左到右计算表达式。请注意,在评估分配时,右侧先于左侧评估。
在第一个示例中,如您所料,nums[1] 被设置为 1,然后 nums[0] 被设置为 2。
在第二个示例中,nums[0] 被设置为 2,然后nums[2]被设置为 1。这是因为在这种情况下,左侧的 nums[nums[0]] 实际上是在引用 nums[2 ] 分配发生时,因为 nums[0] 刚刚被设置为 2。