python - += 到 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 变化?
解决方案
BINARY_ADD
将新对象压入堆栈。该新对象具有新 ID。没有现有对象会更改 ID。字符串和整数是不可变的;它们不会就地更改。
这实际上是理解 Python 的一个关键部分:名称和对象之间的分离。名称只是对程序员的一种方便——注意反汇编中根本没有名称。名称与对象绑定,所有对象都是匿名的并且存在于“对象云”中。 a
开始绑定到匿名字符串对象“xxx”。第一次更改后,a
现在绑定到一个带有“xxxA”的新字符串对象;不再需要字符串对象“xxx”并将被回收。
推荐阅读
- r - 按名称合并几个虚拟变量列
- javascript - 我如何像这样更改 javascript 日期格式-Mon Jun 07 2021 17:44:06 GMT+0300 (שעון ישראל (קיץ)) 到 2021-06-07(按此顺序年/月/日)
- makefile - 无论文件是否更改,都进行重建
- php - 使用 AJAX 和 PHP 检查动态创建的测验问题的答案
- java - 在 ArrayList 上搜索
- spring-boot - 如何使用 WebFlux 设置重定向
- java - 将Maven添加到项目后JavaFX不起作用
- google-cloud-platform - 通过使用“云存储上的文本文件到大查询”数据流模板 GCP 将大查询中的日期格式从 DD-MM-YYYY 转换为 YYYY-MM-DD
- react-native - 函数 CollectionReference.doc() 要求它的第一个参数是非空字符串类型,但它是:对象错误
- swift - 快速找出下周的开始