元组解包顺序改变分配的值
- 2025-03-21 09:07:00
- admin 原创
- 59
问题描述:
我认为两者是相同的。
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]
但结果却不同。
为什么结果不同?(为什么第二个是那个结果?)
解决方案 1:
先决条件- 2 个要点
列表是可变的
列表的主要部分是列表是可变的。这意味着列表的值可以更改。这是您遇到麻烦的原因之一。请参阅文档了解更多信息
评估顺序
另一部分是,在解包元组时,求值从左到右开始。请参阅文档了解更多信息
介绍
当您执行时,和a,b = c,d
的值首先被存储。然后从左侧开始,的值首先更改为,然后的值更改为。c
`da
cb
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]
值保持不变2
。因此print nums
将打印[2, 2, 1]
解决方案 2:
你可以定义一个类来跟踪这个过程:
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)
。
在赋值阶段,第一个方法获取nums[0]
,1
并设置nums[1] = 1
,然后nums[0] = 2
,第二个方法分配nums[0] = 2
,然后获取nums[0]
,2
最后设置nums[2] = 1
。
解决方案 3:
这是因为 python 赋值的优先级是从左到右的。所以在下面的代码中:
nums = [1, 2, 0]
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
它首先将 分配nums[0]
给nums[nums[0]]
平均值nums[1]==1
,然后由于列表是可变对象,因此数字将是:
[1,1,0]
然后nums[nums[0]]
将分配给nums[0]
这意味着nums[0]==2
和:
nums = [2,1,0]
第二部分也是如此。
请注意,这里的重点是列表对象是可变的,当您在一段代码中更改它时,它可以就地更改。因此它会影响其余代码。
评估顺序
Python 从左到右计算表达式的值。请注意,在计算赋值时,先计算右侧的值,然后再计算左侧的值。
解决方案 4:
在第一个例子中,正如您所预料的那样,nums[1] 被设置为 1,然后 nums[0] 被设置为 2。
在第二个例子中,nums[0] 被设置为 2,然后nums[2]被设置为 1。这是因为,在这种情况下,当赋值发生时,左边的 nums[nums[0]] 实际上引用的是 nums[2],因为 nums[0] 刚刚被设置为 2。
扫码咨询,免费领取项目管理大礼包!