【问题标题】:Assignment operation Python赋值操作 Python
【发布时间】:2020-04-16 21:49:57
【问题描述】:

我是 Python 新手,以下问题对我来说很难理解。

a,b,c=1,2,3
a,b,c=c,a,b=b,a,c=c,b,a
print(a,b,c)

这个的输出是 -

(2,3,1)

但我不明白为什么不是 -

(3,2,1)

【问题讨论】:

  • (a, b, c) = (c, a, b) = (b, a, c) = (3, 2, 1),同时记住语句是从右到左评估的,现在更清楚了吗?
  • 这将是您使用调试器的最佳时机!调试器是一个很好的工具,特别是如果你能正确使用它们。如果您使用的是 PyCharm,请按 alt+shift+f9 并使用 alt+f7 逐步完成。

标签: python-3.x variable-assignment assignment-operator


【解决方案1】:

你认为发生了什么

a, b, c = 1, 2, 3
b, a, c = c, b, a
print(a, b, c)
# 2, 3, 1
c, a, b = b, a, c
print(a, b, c)
# 2, 1, 3
a, b, c = c, a, b
print(a, b, c)
# 3, 2, 1

实际发生了什么

a, b, c = 1, 2, 3
# a, b, c = c, a, b = b, a, c = c, b, a
temp = c, b, a
a, b, c = temp
print(a, b, c)
# 3 2 1
c, a, b = temp
print(a, b, c)
# 2 1 3
b, a, c = temp
print(a, b, c)
# 2 3 1

基本上:根据c, b, a从右加载,而存储从左到右。

这可以通过反汇编表达式来证明:

import dis


def chained_assign():
    a, b, c = 1, 2, 3
    a, b, c = c, a, b = b, a, c = c, b, a
    return a, b, c


dis.dis(chained_assign)

输出:

  5           0 LOAD_CONST               4 ((1, 2, 3))
              2 UNPACK_SEQUENCE          3
              4 STORE_FAST               0 (a)
              6 STORE_FAST               1 (b)
              8 STORE_FAST               2 (c)

  6          10 LOAD_FAST                2 (c)
             12 LOAD_FAST                1 (b)
             14 LOAD_FAST                0 (a)
             16 BUILD_TUPLE              3
             18 DUP_TOP
             20 UNPACK_SEQUENCE          3
             22 STORE_FAST               0 (a)
             24 STORE_FAST               1 (b)
             26 STORE_FAST               2 (c)
             28 DUP_TOP
             30 UNPACK_SEQUENCE          3
             32 STORE_FAST               2 (c)
             34 STORE_FAST               0 (a)
             36 STORE_FAST               1 (b)
             38 UNPACK_SEQUENCE          3
             40 STORE_FAST               1 (b)
             42 STORE_FAST               0 (a)
             44 STORE_FAST               2 (c)

  7          46 LOAD_FAST                0 (a)
             48 LOAD_FAST                1 (b)
             50 LOAD_FAST                2 (c)
             52 BUILD_TUPLE              3
             54 RETURN_VALUE

注意第 6 行中 STORE_FASTLOAD_FAST 指令的顺序。

这里有更多的讨论:

【讨论】:

    【解决方案2】:

    正如 norok 所指出的,存储和装载是从不同的方向进行的。如果我们使用下面的代码,我们可以看到 python 在底层做了什么。

    import dis
    
    def foo():
        a, b, c = 1, 2, 3
        a, b, c = c, a, b = b, a, c = c, b, a
    
    dis.dis(foo)
    

    下面是字节码。在 cmets 的右侧,您可以看到变量 abc 的值以及操作结束时的内存堆栈。您将看到DUP_TOP 命令在各个步骤中否定分配,因此只有第一次加载和最后一次存储似乎可以执行任何操作。这也可以解释为什么 a, b, c = a, a, a = b, b, b = c, c, c = b, a, c = c, b, a 仍然评估为 (2, 3, 1)

                                                          # a b c stack
    
    4           0 LOAD_CONST               4 ((1, 2, 3))  # - - - [(1, 2, 3)]
                3 UNPACK_SEQUENCE          3              # - - - [1, 2, 3]
                6 STORE_FAST               0 (a)          # 1 - - [2, 3]
                9 STORE_FAST               1 (b)          # 1 2 - [3]
               12 STORE_FAST               2 (c)          # 1 2 3 []
    
    5          15 LOAD_FAST                2 (c)          # 1 2 3 [3]
               18 LOAD_FAST                1 (b)          # 1 2 3 [3, 2]
               21 LOAD_FAST                0 (a)          # 1 2 3 [3, 2, 1]
               24 BUILD_TUPLE              3              # 1 2 3 [(3, 2, 1)]
               27 DUP_TOP                                 # 1 2 3 [(3, 2, 1), (3, 2, 1)]
               28 UNPACK_SEQUENCE          3              # 1 2 3 [3, 2, 1, (3, 2, 1)]
               31 STORE_FAST               0 (a)          # 3 2 3 [2, 1, (3, 2, 1)]
               34 STORE_FAST               1 (b)          # 3 2 3 [1, (3, 2, 1)]
               37 STORE_FAST               2 (c)          # 3 2 1 [(3, 2, 1)]
               40 DUP_TOP                                 # 3 2 1 [(3, 2, 1), (3, 2, 1)]
               41 UNPACK_SEQUENCE          3              # 3 2 1 [3, 2, 1, (3, 2, 1)]
               44 STORE_FAST               2 (c)          # 3 2 3 [2, 1, (3, 2, 1)]
               47 STORE_FAST               0 (a)          # 2 2 3 [1, (3, 2, 1)]
               50 STORE_FAST               1 (b)          # 2 1 3 [(3, 2, 1)]
               53 UNPACK_SEQUENCE          3              # 2 1 3 [3, 2, 1]
               56 STORE_FAST               1 (b)          # 2 3 3 [2, 1]
               59 STORE_FAST               0 (a)          # 2 3 3 [1]
               62 STORE_FAST               2 (c)          # 2 3 1 []
    

    【讨论】:

    • a, b, c = a, a, a = b, b, b = c, c, c = b, a, c = c, b, a 还是(2, 3, 1) 这个逻辑不解释
    • 也许 this 有帮助 ;-)
    • 是的,我只是在处理字节码并意识到 DUP_TOP 是传递值的原因。那是我第一次像这样挖掘字节码,所以感谢您的推动。
    【解决方案3】:

    这是因为,当你这样写时,它意味着-: a = c = b = c a 的值变为 c,c 的值变为 b,b 的值变为 c。 所以最后变量的变化发生在 b 而不是 a。

    所以输出将是-:

    2 3 1
    

    不是:

    3 2 1
    

    【讨论】:

      猜你喜欢
      • 2011-03-21
      • 2011-07-07
      • 2011-07-19
      • 2016-02-03
      • 1970-01-01
      • 2012-06-18
      • 2018-10-22
      • 2022-01-10
      • 1970-01-01
      相关资源
      最近更新 更多