3

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


案例二:

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]

4

1 回答 1

13

tl; dr:多个赋值(=一行上的多个语句)从左到右计算,而不是从右到左(在计算右侧表达式之后)。

使事情复杂化的是,您正在混合使用元组分配和“正常”分配。

元组赋值使用一个赋值运算符,因此要交换两个变量,请使用:

a, b = b, a

右侧必须评估为与左侧有变量相同数量的元素的元组。你这样做,那很好。

现在,在您的示例中,您不仅在解包元组。当左侧只包含一个变量时,元组不会被解包,只是简单地赋值:

a, b = 1, 2
a = b, a

变成(2, 1).

当您在同一行上使用多个作业时,乐趣就开始了。这些是从左到右处理的。

因此,以下简单示例:

a = b = c = 1

表示a变成1, then b, then c

现在我们可以理解每种情况:

  1. 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.

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

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

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

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

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

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

在这里让您感到困惑的是,在评估右侧之后,分配是从左到右处理的,而不是从右到左处理的。

对于这样的情况,实际上最容易运行代码(包装在函数中),通过dis.dis()函数来​​反汇编 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

于 2012-12-01T08:20:05.837 回答