我在python中声明了四个变量[a = 1,b = 2,c = 3,d = 0],并使用','和'='(简单赋值运算符)将它们交换为一行代码。
我有多个答案并感到困惑。请帮帮我......
案例1:
a=1
b=2
c=3
d=0
a=a,b=b,c
print "a = " + str(a)
print "b = " + str(b)
print "c = " + str(c)
print "d = " + str(d)
案例1的输出:
a = 2
b = 3
c = 3
d = 0
案例2:
a=1
b=2
c=3
d=0
b=a,b=b,c
print "a = " + str(a)
print "b = " + str(b)
print "c = " + str(c)
print "d = " + str(d)
案例2的输出:
a = 2
b = 3
c = 3
d = 0
案例3:
a=1
b=2
c=3
d=0
c=a,b=b,c
print "a = " + str(a)
print "b = " + str(b)
print "c = " + str(c)
print "d = " + str(d)
案例3的输出:
a = 2
b = 3
c = (2,3)
d = 0
案例4:
a=1
b=2
c=3
d=0
d=a,b=b,c
print "a = " + str(a)
print "b = " + str(b)
print "c = " + str(c)
print "d = " + str(d)
案例4的输出:
a = 2
b = 3
c = 3
d = (2,3)
困惑是:
在案例编号3和4中,输出正确(正如我预期的那样)。但在数字1和2的情况下,a的值是2,b的值是3.我希望该值应该是(2,3)。那我的代码有什么问题?
[我的Python版本是2.7]
答案 0 :(得分:13)
tl; dr:多个赋值(一行多个=
语句)从左到右,而不是从右到左(在评估右侧表达式之后)进行评估。 / p>
使问题复杂化的是,你在一个令人兴奋的混音中使用元组赋值和“正常”赋值。
元组赋值使用一个赋值运算符,因此要交换两个变量,请使用:
a, b = b, a
右侧必须评估为与左侧有变量的元素数相同的元组。你做到了,所以没关系。
现在,在您的示例中,您不仅要解包元组。当左侧仅包含一个变量时,元组未解包,只是简单地分配:
a, b = 1, 2
a = b, a
变为(2, 1)
。
当您在同一行上使用多个分配时,乐趣就开始了。这些是从左到右处理的。
所以,下面是一个简单的例子:
a = b = c = 1
表示a
变为1
,然后变为b
,然后变为c
。
现在我们可以理解每个案例:
a=a,b=b,c
,其中a = 1
,b = 2
,c = 3
。
这变为:评估b, c
- > (2, 3)
,然后将其分配给a
- > a = (2, 3)
。然后将其分配给a, b
,a = 2
,b = 3
。结果:a = 2
,b = 3
,c = 3
。
b=a,b=b,c
,其中a = 1
,b = 2
,c = 3
。
与之前的情况相同,但现在先设置b = (2, 3)
,然后再设置b = 3
,结果与案例1相同。
c=a,b=b,c
,其中a = 1
,b = 2
,c = 3
。
右侧的输入与案例1和2相同,但现在我们首先设置c = (2, 3)
。最终结果符合预期,a = 2
,b = 3
,c = (2, 3)
。
d=a,b=b,c
,其中a = 1
,b = 2
,c = 3
。
与案例3相同,但现在我们设置了d
。没有惊喜。
让您感到困惑的是,在评估右侧之后,分配从左到右处理,不从右到左处理。
对于这样的情况,实际上最简单的方法是运行代码(包含在函数中),通过dis.dis()
function来反汇编python字节码:
>>> import dis
>>> def f(): a=a,b=b,c
...
>>> dis.dis(f)
1 0 LOAD_FAST 0 (b)
3 LOAD_GLOBAL 0 (c)
6 BUILD_TUPLE 2
9 DUP_TOP
10 STORE_FAST 1 (a)
13 UNPACK_SEQUENCE 2
16 STORE_FAST 1 (a)
19 STORE_FAST 0 (b)
22 LOAD_CONST 0 (None)
25 RETURN_VALUE
这是第一个案例;请注意在BUILD_TUPLE
和DUP_TOP
操作码之后(后者在堆栈上创建额外的副本以提供额外的赋值),首先发生的是STORE_FAST操作> a
,然后是UNPACK_SEQUENCE
(元组赋值操作码),然后将结果存储到a
和b
。