Python string interning
internals (2)
Esto es específico de la implementación, pero es probable que el intérprete esté internando las constantes de tiempo de compilación, pero no los resultados de las expresiones en tiempo de ejecución.
En lo que sigue utilizo CPython 2.7.3.
En el segundo ejemplo, la expresión "strin"+"g"
se evalúa en tiempo de compilación y se reemplaza por "string"
. Esto hace que los dos primeros ejemplos se comporten de la misma manera.
Si examinamos los bytecodes, veremos que son exactamente los mismos:
# 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)
El tercer ejemplo implica una concatenación en tiempo de ejecución, cuyo resultado no se interna automáticamente:
# 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
Si intern()
manualmente intern()
el resultado de la tercera expresión, obtendría el mismo objeto que antes:
>>> s3a = "strin"
>>> s3 = s3a + "g"
>>> s3 is "string"
False
>>> intern(s3) is "string"
True
Si bien esta pregunta no tiene ningún uso real en la práctica, tengo curiosidad sobre cómo Python realiza el interinato de cuerdas. Me di cuenta de lo siguiente.
>> "string" is "string"
>> True
Esto es lo que esperaba.
También puedes hacer esto.
>> "strin"+"g" is "string"
>> True
¡Y eso es bastante inteligente!
Pero no puedes hacer esto.
>> s1 = "strin"
>> s2 = "string"
>> s1+"g" is s2
>> False
¿Por qué Python no evaluaría s1+"g"
, se daría cuenta de que es lo mismo que s1
y lo dirigirá a la misma dirección? ¿Qué está sucediendo realmente en ese último bloque para que devuelva False
?
Caso 1
>>> x = "123"
>>> y = "123"
>>> x == y
True
>>> x is y
True
>>> id(x)
50986112
>>> id(y)
50986112
Caso 2
>>> x = "12"
>>> y = "123"
>>> x = x + "3"
>>> x is y
False
>>> x == y
True
Ahora, su pregunta es por qué el ID es el mismo en el caso 1 y no en el caso 2.
En el caso 1, ha asignado un literal de cadena "123"
a y
.
Como la cadena es inmutable, tiene sentido que el intérprete almacene literalmente la cadena solo una vez y señale todas las variables al mismo objeto.
Por lo tanto, ves el id como idéntico.
En el caso 2, está modificando x
usando concatenación. Tanto x
como y
tienen los mismos valores, pero no la misma identidad.
Ambos apuntan a diferentes objetos en la memoria. Por lo tanto, tienen una id
diferente y el operador devuelve False