Python: comportamiento id () en el intérprete

Me encontré con este extraño comportamiento que solo ocurre en una sesión interactiva de Python, pero no cuando escribo un script y lo ejecuto.

La cadena es un tipo de datos inmutable en Python, por lo tanto:

>>> s2='string' >>> s1='string' >>> s1 is s2 True 

Ahora, la parte rara:

 >>> s1='a string' >>> s2='a string' >>> s1 is s2 False 

He visto que tener un espacio en blanco en la cadena causa este comportamiento. Si pongo esto en un script y lo ejecuto, el resultado es Verdadero en ambos casos.

¿Alguien tendría una pista sobre esto? Gracias.

EDITAR:

De acuerdo, las preguntas y respuestas anteriores dan algunas ideas. Ahora aquí hay otro experimento:

 >>> s2='astringbstring' >>> s1='astringbstring' >>> s1 is s2 True 

En este caso, las cadenas son definitivamente más largas que 'a string' , pero aún tienen los mismos identificadores.

Muchas gracias a @eryksun por las correcciones!

Esto se debe a un mecanismo de interning en Python:

Introduzca la cadena en la tabla de cadenas “internadas” y devuelva la cadena internada, que es la cadena en sí misma o una copia. Las cadenas internas son útiles para obtener un poco de rendimiento en la búsqueda del diccionario: si las claves de un diccionario están internadas y la clave de búsqueda se internan, las comparaciones de claves (después del hashing) se pueden realizar mediante una comparación de puntero en lugar de una comparación de cadena. Normalmente, los nombres utilizados en los progtwigs de Python se internan automáticamente, y los diccionarios que se utilizan para guardar los atributos de módulo, clase o instancia tienen claves internadas.

Cambiado en la versión 2.3: las cadenas internas no son inmortales (como solían estar en Python 2.2 y anteriores); debe mantener una referencia al valor de retorno de intern () para beneficiarse de él.

CPython internará automáticamente ciertas cadenas cortas (cadenas de 1 letra, palabras clave, cadenas sin espacios que se han asignado) para boost la velocidad de búsqueda y la velocidad de comparación: por ejemplo, 'dog' is 'dog' será una comparación de puntero en lugar de una cadena completa comparación. Sin embargo, el internado automático para todas las cadenas (más largas) requiere mucha más memoria, lo que no siempre es factible, por lo que es posible que no compartan la misma identidad que hace que los resultados de id() diferentes, por ejemplo:

 # different id when not assigned In [146]: id('dog') Out[146]: 4380547672 In [147]: id('dog') Out[147]: 4380547552 # if assigned, the strings will be interned (though depends on implementation) In [148]: a = 'dog' In [149]: b = 'dog' In [150]: id(a) Out[150]: 4380547352 In [151]: id(b) Out[151]: 4380547352 In [152]: a is b Out[152]: True 

Para los enteros, al menos en mi máquina, CPython internará automáticamente hasta 256 automáticamente:

 In [18]: id(256) Out[18]: 140511109257408 In [19]: id(256) Out[19]: 140511109257408 In [20]: id(257) Out[20]: 140511112156576 In [21]: id(257) Out[21]: 140511110188504 

ACTUALIZACIÓN gracias a @eryksun : en este caso, la cadena 'a string' no está internada porque CPython solo interna cadenas sin espacios , no por la longitud que asumí al instante: por ejemplo, letras ASCII, dígitos y subrayado.

Para más detalles, también puede consultar la respuesta de Alex Martelli aquí .