Интернирование строк 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?

2 65

2 ответа:

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

в дальнейшем я использую 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

корпус 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