¿Por qué (0-6) es -6 = Falso?

Posible duplicado:
El operador “es” de Python se comporta inesperadamente con los enteros

Hoy traté de depurar mi proyecto y después de unas horas de análisis obtuve esto:

>>> (0-6) is -6 False 

pero,

 >>> (0-5) is -5 True 

¿Podría explicarme por qué? Tal vez esto sea algún tipo de error o comportamiento muy extraño.

 > Python 2.7.3 (default, Apr 24 2012, 00:00:54) [GCC 4.7.0 20120414 (prerelease)] on linux2 >>> type(0-6)  >>> type(-6)  >>> type((0-6) is -6)  >>> 

    Todos los enteros de -5 a 256 inclusive se almacenan en la memoria caché como objetos globales que comparten la misma dirección con CPython, por lo que is pasa la prueba.

    Este artefacto se explica en detalle en http://www.laurentluce.com/posts/python-integer-objects-implementation/ , y podríamos verificar el código fuente actual en http://hg.python.org/cpython/file /tip/Objects/longobject.c .

    Se utiliza una estructura específica para referir a enteros pequeños y compartirlos para que el acceso sea rápido. Es una matriz de 262 punteros a objetos enteros. Esos objetos enteros se asignan durante la inicialización en un bloque de objetos enteros que vimos anteriormente. El rango de los enteros pequeños es de -5 a 256. Muchos progtwigs de Python pasan mucho tiempo usando enteros en ese rango, por lo que esta es una decisión inteligente.

    Esto es solo un detalle de implementación de CPython y no debe confiar en esto. Por ejemplo, PyPy implementó el id del entero para devolverse, por lo que (0-6) is -6 siempre es cierto, incluso si son “objetos diferentes” internamente; también le permite configurar si habilitar este almacenamiento en caché de enteros, e incluso establecer los límites inferior y superior. Pero en general, los objetos recuperados de diferentes orígenes no serán idénticos. Si quieres comparar la igualdad, solo usa == .

    Python almacena enteros en el rango -5 – 256 en el intérprete: tiene un conjunto de objetos enteros desde los cuales se devuelven estos enteros. Es por eso que esos objetos son los mismos: (0-5) y -5 pero no (0-6) y -6 ya que estos se crean en el momento.

    Aquí está la fuente en el código fuente de CPython:

     #define NSMALLPOSINTS 257 #define NSMALLNEGINTS 5 static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; 

    ( ver código fuente de CPython : /trunk/Objects/intobject.c ). El código fuente incluye el siguiente comentario:

     /* References to small integers are saved in this array so that they can be shared. The integers that are saved are those in the range -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive). */ 

    El operador is comparará ( -5 ) como iguales porque son el mismo objeto (la misma ubicación de memoria) pero los otros dos enteros nuevos ( -6 ) estarán en diferentes ubicaciones de memoria (y luego no volverá True ) . Tenga en cuenta que 257 en el código fuente anterior es para los enteros positivos, de modo que es 0 - 256 (inclusive).

    ( fuente )

    No es un error. No es una prueba de igualdad. == dará los resultados esperados.

    La razón técnica para este comportamiento es que una implementación de Python es libre de tratar diferentes instancias del mismo valor constante como el mismo objeto o como objetos diferentes. La implementación de Python que está utilizando elige que ciertas constantes pequeñas compartan el mismo objeto por razones de ahorro de memoria. No puede confiar en que este comportamiento sea la misma versión que la versión o en diferentes implementaciones de Python.

    Está sucediendo porque CPython almacena en caché algunos enteros pequeños y cadenas pequeñas y le da a cada instancia de ese objeto un mismo id() .

    (0-5) y -5 tiene el mismo valor para id() , que no es cierto para 0-6 y -6

     >>> id((0-6)) 12064324 >>> id((-6)) 12064276 >>> id((0-5)) 10022392 >>> id((-5)) 10022392 

    Del mismo modo para cuerdas:

     >>> x = 'abc' >>> y = 'abc' >>> x is y True >>> x = 'a little big string' >>> y = 'a little big string' >>> x is y False 

    Para obtener más detalles sobre el almacenamiento en caché de cadenas, lea: is operador se comporta de manera diferente al comparar cadenas con espacios