Cuerda de python con espacio y sin espacio al final e inmutabilidad.

Aprendí que en algunas clases inmutables, __new__ puede devolver una instancia existente: esto es lo que a veces hacen los tipos int , str y tuple para valores pequeños.

Pero, ¿por qué los siguientes dos fragmentos difieren en el comportamiento?

Con un espacio al final:

 >>> a = 'string ' >>> b = 'string ' >>> a is b False 

Sin un espacio:

 >>> c = 'string' >>> d = 'string' >>> c is d True 

¿Por qué el espacio trae la diferencia?

Related of "Cuerda de python con espacio y sin espacio al final e inmutabilidad."

Esta es una peculiaridad de cómo la implementación de CPython elige almacenar en cadena los literales. Los literales de cadena con el mismo contenido pueden referirse al mismo objeto de cadena, pero no tienen que hacerlo. 'string' pasa a ser internada automáticamente cuando 'string ' no se debe a que 'string' solo contiene caracteres permitidos en un identificador de Python. No tengo idea de por qué ese es el criterio que eligieron, pero lo es. El comportamiento puede ser diferente en diferentes versiones o implementaciones de Python.

Desde el código fuente de CPython 2.7, stringobject.h , línea 28:

Las cadenas internas (ob_sstate) intentan garantizar que solo exista un objeto de cadena con un valor determinado, por lo que las pruebas de igualdad pueden ser una comparación de puntero. Esto generalmente se restringe a cadenas que “parecen” identificadores de Python, aunque el interno () incorporado se puede usar para forzar la internación de cualquier cadena.

Puede ver el código que hace esto en Objects/codeobject.c :

 /* Intern selected string constants */ for (i = PyTuple_Size(consts); --i >= 0; ) { PyObject *v = PyTuple_GetItem(consts, i); if (!PyString_Check(v)) continue; if (!all_name_chars((unsigned char *)PyString_AS_STRING(v))) continue; PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i)); } 

Además, tenga en cuenta que la internación es un proceso separado de la fusión de literales de cadena por el comstackdor de bytecode de Python. Si deja que el comstackdor compile las asignaciones a y b juntas, por ejemplo, colocándolas en un módulo o an if True: encontrará que a y b serían la misma cadena.

Este comportamiento no es consistente y, como otros han mencionado, depende de la variante de Python que se está ejecutando. Para una discusión más profunda, vea esta pregunta .

Si desea asegurarse de que se está utilizando el mismo objeto, puede forzar la internación de cadenas por parte del intern nombre apropiado:

interno (…) interno (cadena) -> cadena

 ``Intern'' the given string. This enters the string in the (global) table of interned strings whose purpose is to speed up dictionary lookups. Return the string itself or the previously interned string object with the same value. 
 >>> a = 'string ' >>> b = 'string ' >>> id(a) == id(b) False >>> a = intern('string ') >>> b = intern('string ') >>> id(a) == id(b) True 

Nota en Python3, tienes que importar explícitamente el interno from sys import intern .