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» больше не нужен и будет восстановлен.

Другие вопросы по тегам