为什么(0-6)是-6 =假?

可能重复:
Python“是”运算符意外地用整数行为

今天,我试图debugging我的项目,经过几个小时的分析,我得到了这个:

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

但,

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

你能向我解释一下,为什么? 也许这是某种错误或非常奇怪的行为。

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

从-5到256的所有整数被caching为与CPython共享相同地址的全局对象,因此testing通过。

这个工件在http://www.laurentluce.com/posts/python-integer-objects-implementation/中详细解释,我们可以在http://hg.python.org/cpython/file中检查当前的源代码/tip/Objects/longobject.c

一个特定的结构被用来引用小整数并共享它们,因此访问速度很快。 它是一个整数对象的指针数组。 这些整数对象在我们上面看到的一个整数对象块的初始化过程中被分配。 小整数的范围是从-5到257.许多Python程序花费了大量的时间使用整数范围,所以这是一个明智的决定。

这只是CPython的一个实现细节,你不应该依赖这个。 例如, PyPy实现了返回自身的整数的id ,所以即使它们在内部是“不同的对象”, (0-6) is -6也总是为真。 它也允许你configuration是否启用这个整数caching,甚至设置下限和上限。 但一般来说,从不同来源检索的对象将不会相同。 如果你想比较平等,只需使用==

Python在解释器中存储范围为-5 – 256的整数:它有一个整型对象池,从这些整型对象中返回这些整数。 这就是为什么这些对象是相同的: (0-5)-5但不是(0-6)-6因为这些是在现场创build的。

以下是CPython源代码的源代码:

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

( 查看CPython源代码 : /trunk/Objects/intobject.c )。 源代码包括以下评论:

 /* 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). */ 

然后is运算符会将它们( -5 )相等,因为它们是相同的对象(相同的内存位置),但其他两个新的整数( -6 )将在不同的内存位置(然后不会返回True ) 。 请注意,上述源代码中的257是正整数,因此是0 - 256 (含)。

( 来源 )

这不是一个错误。 is不是一个平等的考验。 ==会给出预期的结果。

这种行为的技术原因是Python实现可以自由地将同一个常量值的不同实例视为同一个对象或不同的对象。 您正在使用的Python实现select使某些小常量共享相同的对象,以节省内存的原因。 你不能依赖于这个行为与版本相同的版本,或者不同的Python实现。

这是因为CPythoncaching了一些小的整数和小的string,并为该对象的每个实例提供了相同的id()

(0-5)-5对于id()具有相同的值,这对于0-6-6是不正确的

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

类似的string:

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

有关stringcaching的更多详细信息,请参阅: 当比较string与空格时,运算符的行为是否有所不同