dis код от += до INPLACE_ADD - объясните, почему это работает таким образом
У меня очень простая функция 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?
1 ответ
BINARY_ADD
помещает новый объект в стек. У этого нового объекта новый идентификатор. Ни один из существующих объектов никогда не меняет ID. Строки и целые числа неизменяемы; они не меняются на месте.
На самом деле это ключевая часть понимания Python: разделение имен и объектов. Имена - это просто удобство для программиста - обратите внимание, что в дизассемблере имен нет вообще. Имена привязаны к объектам, все они анонимны и находятся в «облаке объектов». начинается с привязки к анонимному строковому объекту «xxx». После вашего первого изменения
a
теперь привязан к новому строковому объекту с «xxxA»; строковый объект «xxx» больше не нужен и будет восстановлен.