Python交换值操作调整赋值顺序为何产生不同运行结果?
Python顺序赋值下标计算导致的交换结果差异问题
问题现象
给定输入列表[1,2,3,4],预期交换索引0和索引1位置的元素,得到输出[2,1,3,4]。
以下代码可以得到正确结果:
a = [1,2,3,4] a[a[0]], a[0] = a[0],a[a[0]] # 输出:[2, 1, 3, 4]
仅调换等号左侧赋值目标的书写顺序,就会得到错误输出:
a = [1,2,3,4] a[0],a[a[0]] = a[a[0]],a[0] # 输出:[2, 2, 1, 4]
作为对比,普通变量交换时,调换赋值目标顺序不会改变结果,以下两种写法执行后print(a,b)均输出2,1:
a = 1 b= 2 a,b = b,a # 写法1 b,a = a,b # 写法2 print(a,b) # 两种写法均输出2,1
核心原因
Python的多变量赋值遵循两个固定规则:
- 等号右侧的所有表达式,会在任何赋值操作开始前全部计算完成,打包成一个临时元组,这一步两种列表交换写法没有区别。
- 等号左侧的赋值目标,会严格从左到右依次执行赋值,每完成一个赋值,变量/列表的状态就会立刻更新,后续赋值目标的表达式求值会基于更新后的状态计算。
两种列表交换写法的执行拆解
初始状态:a = [1,2,3,4],即a[0] = 1,a[1] = 2。
- 正确写法执行流程:
a[a[0]], a[0] = a[0],a[a[0]]- 第一步先算右侧:
a[0]是1,a[a[0]]即a[1]是2,右侧临时元组为(1, 2) - 从左到右给左侧目标赋值:
- 第一个目标是
a[a[0]]:此时还没做任何赋值,a[0]还是1,对应位置是a[1],把右侧第一个值1赋给a[1],此时列表变为[1,1,3,4] - 第二个目标是
a[0]:把右侧第二个值2赋给a[0],此时列表变为[2,1,3,4],和预期结果一致。
- 第一个目标是
- 第一步先算右侧:
- 错误写法执行流程:
a[0],a[a[0]] = a[a[0]],a[0]- 第一步先算右侧:
a[a[0]]即a[1]是2,a[0]是1,右侧临时元组为(2, 1) - 从左到右给左侧目标赋值:
- 第一个目标是
a[0]:把右侧第一个值2赋给a[0],此时列表已经变为[2,2,3,4] - 第二个目标是
a[a[0]]:此时要先计算索引值,a[0]已经被改成了2,对应位置是a[2],把右侧第二个值1赋给a[2],最终列表变为[2,2,1,4],出现错误。
- 第一个目标是
- 第一步先算右侧:
普通变量交换无差异的原因
普通变量交换时,等号左侧的赋值目标是直接的变量名,不需要额外计算索引/位置:写a就对应变量a,写b就对应变量b,不会因为a的值被修改,导致b这个目标的指向发生变化。
以写法2b,a = a,b为例:
- 先算右侧得到临时元组
(1,2) - 从左到右赋值:先把1赋给b,再把2赋给a,最终a=2、b=1,和写法1结果完全一致。
简单总结:只要左侧赋值目标的定位不依赖前面赋值修改过的值,调换赋值顺序就不会影响最终结果;一旦左侧目标是需要计算的下标、属性等表达式,且表达式依赖前面会被修改的变量,顺序就会直接影响结果。
内容的提问来源于stack exchange,提问作者back2back
相关产品推荐
相关产品推荐

