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

最佳答案

tl; dr:多个赋值(一行上的多个 = 语句)从左到右计算,而不是从右到左(在计算右侧表达式之后)。
更复杂的是,您正在混合使用元组分配和“正常”分配。
元组赋值使用一个赋值运算符,因此要交换两个变量,请使用:

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 = 1b = 2c = 3
    这变成:评估 b, c -> (2, 3) ,然后将其分配给 a -> a = (2, 3) 。然后将它分配给 a, b ,所以 a = 2b = 3 。结果: a = 2b = 3c = 3
  • b=a,b=b,c ,其中 a = 1b = 2c = 3
    与之前的情况相同,但现在先设置 b = (2, 3),然后再次设置 b = 3,结果与情况 1 相同。
  • c=a,b=b,c ,其中 a = 1b = 2c = 3
    右侧的输入与案例 1. 和 2. 相同,但现在我们首先设置 c = (2, 3) 。最终结果如预期, a = 2b = 3c = (2, 3)
  • d=a,b=b,c ,其中 a = 1b = 2c = 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_TUPLEDUP_TOP 操作码(后者在堆栈上创建一个额外的副本以提供额外的赋值)之后,发生的第一件事是 STORE_FAST 上的 a 操作,然后是 UNPACK_SEQUENCE(元组赋值操作码),以然后将结果存储到 ab 中。

    关于python - 简单的赋值运算符在 Python 中变得复杂,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13657704/

    10-14 18:56