简单的赋值运算符在Python中变得复杂

时间:2012-12-01 08:16:59

标签: python operators variable-assignment

我在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]

1 个答案:

答案 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

现在我们可以理解每个案例:

  1. a=a,b=b,c,其中a = 1b = 2c = 3

    这变为:评估b, c - > (2, 3),然后将其分配给a - > a = (2, 3)。然后将其分配给a, ba = 2b = 3。结果:a = 2b = 3c = 3

  2. b=a,b=b,c,其中a = 1b = 2c = 3

    与之前的情况相同,但现在先设置b = (2, 3),然后再设置b = 3,结果与案例1相同。

  3. c=a,b=b,c,其中a = 1b = 2c = 3

    右侧的输入与案例1和2相同,但现在我们首先设置c = (2, 3)。最终结果符合预期,a = 2b = 3c = (2, 3)

  4. d=a,b=b,c,其中a = 1b = 2c = 3

    与案例3相同,但现在我们设置了d。没有惊喜。

  5. 让您感到困惑的是,在评估右侧之后,分配从左到右处理,从右到左处理。

    对于这样的情况,实际上最简单的方法是运行代码(包含在函数中),通过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_TUPLEDUP_TOP操作码之后(后者在堆栈上创建额外的副本以提供额外的赋值),首先发生的是STORE_FAST操作> a ,然后是UNPACK_SEQUENCE(元组赋值操作码),然后将结果存储到ab