Интерпретация строки Python

Хотя этот вопрос не имеет реального применения на практике, мне любопытно, как Python выполняет интернирование строк. Я заметил следующее.

>> "string" is "string"
>> True

Это как я и ожидал.

Вы также можете сделать это.

>> "strin"+"g" is "string"
>> True

И это довольно умно!

Но ты не можешь сделать это.

>> s1 = "strin"
>> s2 = "string"
>> s1+"g" is s2
>> False

Почему Python не может оценить s1+"g" и понять, что он такой же, как s1 и указать на тот же адрес? Что на самом деле происходит в последнем блоке, чтобы вернуть значение False?

Ответ 1

Это специфично для реализации, но ваш интерпретатор, вероятно, ставит постоянные константы компиляции, но не результаты выражений во время выполнения.

В дальнейшем я использую CPython 2.7.3.

Во втором примере выражение "strin"+"g" оценивается во время компиляции и заменяется на "string". Это приводит к тому, что первые два примера ведут себя одинаково.

Если мы рассмотрим байткоды, мы увидим, что они точно такие же:

  # s1 = "string"
  2           0 LOAD_CONST               1 ('string')
              3 STORE_FAST               0 (s1)

  # s2 = "strin" + "g"
  3           6 LOAD_CONST               4 ('string')
              9 STORE_FAST               1 (s2)

Третий пример включает конкатенацию времени выполнения, результат которой не выполняется автоматически:

  # s3a = "strin"
  # s3 = s3a + "g"
  4          12 LOAD_CONST               2 ('strin')
             15 STORE_FAST               2 (s3a)

  5          18 LOAD_FAST                2 (s3a)
             21 LOAD_CONST               3 ('g')
             24 BINARY_ADD          
             25 STORE_FAST               3 (s3)
             28 LOAD_CONST               0 (None)
             31 RETURN_VALUE        

Если вы должны вручную intern() получить результат третьего выражения, вы получите тот же объект, что и раньше:

>>> s3a = "strin"
>>> s3 = s3a + "g"
>>> s3 is "string"
False
>>> intern(s3) is "string"
True

Ответ 2

Случай 1

>>> x = "123"  
>>> y = "123"  
>>> x == y  
True  
>>> x is y  
True  
>>> id(x)  
50986112  
>>> id(y)  
50986112  

Случай 2

>>> x = "12"
>>> y = "123"
>>> x = x + "3"
>>> x is y
False
>>> x == y
True

Теперь, ваш вопрос, почему идентификатор тот же в случае 1, а не в случае 2.
В случае 1 вы назначили строковый литерал "123" до x и y.

Так как строка неизменяема, интерпретатор имеет смысл хранить строковый литерал только один раз и указывать все переменные на один и тот же объект.
Следовательно, вы видите идентификатор идентичным.

В случае 2 вы изменяете x с помощью конкатенации. Оба x и y имеют одинаковые значения, но не идентичны.
Оба указывают на разные объекты в памяти. Следовательно, они имеют разные операторы id и is, возвращенные False