Python-строку интернирование
хотя этот вопрос не имеет реальной пользы на практике, мне любопытно, как Python делает string interning. Я заметил следующее.
>> "string" is "string"
>> True
это, как я ожидал.
вы также можете сделать это.
>> "strin"+"g" is "string"
>> True
и это очень умно!
но вы не можете этого сделать.
>> s1 = "strin"
>> s2 = "string"
>> s1+"g" is s2
>> False
почему бы Python не оценить s1+"g"
, поймите, что это то же самое, что s1
и указать на тот же адрес? Что на самом деле происходит в этом последнем блоке, чтобы он вернулся False
?
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"
to x
и y
.
поскольку string неизменяемы, интерпретатору имеет смысл хранить строковый литерал только один раз и указывать все переменные на один и тот же объект.
Следовательно, вы видите id как идентичный.
в случае 2, вы изменяете x
используя конкатенацию. Оба!--3--> и y
имеет те же значения, но не тот же идентификатор.
Оба указывают на разные объекты в памяти. Следовательно, у них разные id
и is
оператор вернулся False