首页 > 解决方案 > a,b = b,a 为什么这样有错误的结果

问题描述

l = [2,3,1,2,4,5]
l[0],l[l[0]] =l[l[0]],l[0]
print(l)

#wrong result



l = [2,3,1,2,4,5]
l[l[0]],l[0] =l[0],l[l[0]]
print(l)

#correct result

我崩溃了~

第二个是之间的结果

l[0],l[l[0]] =l[l[0]],l[0]

l[0] = l[l[0]]
l[l[0]] = l[0]

结果也不一样

标签: python-3.x

解决方案


好吧,让我们抛开你可能不应该做任何如此复杂的事情的事实:-)

该语句将(a, b) = (c, d)元组分配给变量元组,并且在完成任何分配之前计算值。

但是,对变量的赋值是有序的,每个变量都在不同的操作中计算和赋值。因此,请检查以下代码(使用b代替a[something]以希望使其更清晰):

>>> a = [0, 1] ; b = 0 ; (b, a[b]) = (1, 99) ; print(a)
[0, 99]

你会得到[0, 99],因为 to 的分配1发生在 tob分配之前99,更a[b]重要的是,在计算出实际引用的对象之前a[b]

所以第二个赋值是给a[1 (= changed b)]变量而不是那个a[0 (= original b)],因为b那时已经改变了。

如果您恢复使用列表元素而不是b

>>> a = [0, 1] ; (a[0], a[a[0]]) = (1, 99) ; print(a)
[1, 99]

唯一的区别是它a[0]也发生了变化,因为这是您用于索引的对象,而不是b.


你的原因:

l[0] = l[l[0]]
l[l[0]] = l[0]

片段不起作用是因为那甚至还没有接近交换。它是有效的:

a = b
b = a

最终会得到a并且b 两者都具有最初的值b。一个更“交换”的版本是:

tmp = b
b = a
a = tmp

这也适用于您的变体使用a[a[0]],因为这三行中的每一行都保证在下一行开始之前完全执行。

底线是,虽然元组赋值是 Python 的一个非常强大的特性,但它确实有一些微妙的边缘情况可能会导致悲伤。假设您避开这些情况,它仍然值得使用。


推荐阅读