首页 > 解决方案 > += 到 INPLACE_ADD 的 dis 代码 - 解释为什么它以这种方式工作

问题描述

我有一个非常简单的函数 f,使用 dis.dis 我反汇编它:

def f():
  a = "xxx"
  print(id(a))
  a = a + "A"
  print(id(a))
  a = a + "B"
  print(id(a))
f()

from dis import dis
print(dis(f))

https://pd.codechef.com/docs/py/2.7.9/library/dis.html我知道:

INPLACE_ADD():就地实现 TOS = TOS1 + TOS。

我的问题评论的输出是:

140387882962224
140387687265136
140387687265136
  2           0 LOAD_CONST               1 ('xxx')
              2 STORE_FAST               0 (a)

  3           4 LOAD_GLOBAL              0 (print) # id(a)->140387882962224
              6 LOAD_GLOBAL              1 (id)
              8 LOAD_FAST                0 (a)
             10 CALL_FUNCTION            1
             12 CALL_FUNCTION            1
             14 POP_TOP

  4          16 LOAD_FAST                0 (a)     # id(a) is 140387882962224, TOS = 'xxx'
             18 LOAD_CONST               2 ('A')   # TOS = 'A', TOS1 = 'xxx'
             20 BINARY_ADD                         # TOS = TOS1+TOS = 'xxx'+'A' = 'xxxA'
             22 STORE_FAST               0 (a)     # id(a) is 140387882962224?

  5          24 LOAD_GLOBAL              0 (print) id(a)->140387687265136
             26 LOAD_GLOBAL              1 (id)
             28 LOAD_FAST                0 (a)
             30 CALL_FUNCTION            1
             32 CALL_FUNCTION            1
             34 POP_TOP

  6          36 LOAD_FAST                0 (a)
             38 LOAD_CONST               3 ('B')
             40 BINARY_ADD
             42 STORE_FAST               0 (a)

  7          44 LOAD_GLOBAL              0 (print)
             46 LOAD_GLOBAL              1 (id)
             48 LOAD_FAST                0 (a)
             50 CALL_FUNCTION            1
             52 CALL_FUNCTION            1
             54 POP_TOP
             56 LOAD_CONST               0 (None)
             58 RETURN_VALUE

我在哪里可以看到字节码中 a 的 id 变化?

标签: python

解决方案


BINARY_ADD将新对象压入堆栈。该新对象具有新 ID。没有现有对象会更改 ID。字符串和整数是不可变的;它们不会就地更改。

这实际上是理解 Python 的一个关键部分:名称和对象之间的分离。名称只是对程序员的一种方便——注意反汇编中根本没有名称。名称与对象绑定,所有对象都是匿名的并且存在于“对象云”中。 a开始绑定到匿名字符串对象“xxx”。第一次更改后,a现在绑定到一个带有“xxxA”的新字符串对象;不再需要字符串对象“xxx”并将被回收。


推荐阅读