hen*_*nry 48 python indexing list tuple-packing
我认为两者是相同的.
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]
Run Code Online (Sandbox Code Playgroud)
但结果却不同.
为什么结果不同?(为什么会产生第二个?)
Bha*_*Rao 46
列表是可变的
列表中的主要部分是列表是可变的.这意味着可以更改列表的值.这就是你遇到麻烦的原因之一.有关详细信息,请参阅文档
评估顺序
另一部分是在解包元组时,评估从左到右开始.有关详细信息,请参阅文档
当你执行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]]
Run Code Online (Sandbox Code Playgroud)
nums[0]最初是1和nums[nums[0]]是2因为它的计算结果nums[1].因此1,2现在存储在内存中.
现在,元组拆包从左侧发生,所以
nums[nums[0]] = nums[1] = 1 # NO side Effect.
nums[0] = 2
Run Code Online (Sandbox Code Playgroud)
因此print nums将打印[2, 1, 0]
但是在这种情况下
nums = [1, 2, 0]
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
nums[1]价值保持不变2.因此print nums将打印[2, 2, 1]
eph*_*eph 18
您可以定义一个类来跟踪该过程:
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)
Run Code Online (Sandbox Code Playgroud)
对于第一种方法:
nums = MyList([1, 2, 0])
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
Run Code Online (Sandbox Code Playgroud)
输出是:
get 0
get 0
get 1
get 0
set 1, 1
set 0, 2
Run Code Online (Sandbox Code Playgroud)
而第二种方法:
nums = MyList([1, 2, 0])
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]
Run Code Online (Sandbox Code Playgroud)
输出是:
get 0
get 1
get 0
set 0, 2
get 0
set 2, 1
Run Code Online (Sandbox Code Playgroud)
在这两种方法中,前三行与元组生成相关,而后三行与赋值相关.第一种方法的右侧元组是(1, 2)第二种方法(2, 1).
在分配阶段,第一种方法得到nums[0],其是1,和设置nums[1] = 1,然后nums[0] = 2,第二种方法分配nums[0] = 2,然后得到nums[0]其是2,最后设置nums[2] = 1.
Kas*_*mvd 10
这是因为python赋值优先级从左到右.所以在下面的代码中:
nums = [1, 2, 0]
nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
Run Code Online (Sandbox Code Playgroud)
它首先分配了nums[0]to nums[nums[0]]means nums[1]==1,然后由于列表是可变对象,nums将是:
[1,1,0]
Run Code Online (Sandbox Code Playgroud)
然后nums[nums[0]]将分配给nums[0]哪些方式nums[0]==2和:
nums = [2,1,0]
Run Code Online (Sandbox Code Playgroud)
就像第二部分一样.
请注意,重要的一点是列表对象是可变的,当您在一段代码中更改它时,它可以就地更改.因此它会影响其余的代码.
Python从左到右评估表达式.请注意,在评估分配时,右侧在左侧之前进行评估.