为什么 (0-6) 是 -6 = False?[重复]
- 2025-03-10 08:52:00
- admin 原创
- 57
问题描述:
我在调试一些代码时发现了一些奇怪的东西。显然,
>>> (0-6) is -6
False
但,
>>> (0-5) is -5
True
为什么会发生这种情况?
解决方案 1:
所有从 -5 到 256 的整数(包括 -5 到 256)都被缓存为与 CPython 共享同一地址的全局对象,因此is
测试通过。
该工件在http://www.laurentluce.com/posts/python-integer-objects-implementation/中有详细解释,我们可以在http://hg.python.org/cpython/file/tip/Objects/longobject.c中查看当前的源代码。
使用特定结构来引用小整数并共享它们,以便快速访问。它是一个包含 262 个指向整数对象的指针的数组。这些整数对象在初始化期间分配在我们上面看到的整数对象块中。小整数的范围是 -5 到 256。许多 Python 程序花费大量时间使用该范围内的整数,因此这是一个明智的决定。
这只是 CPython 的一个实现细节,您不应该依赖它。例如,PyPy实现了id
整数的返回值以返回其自身,因此(0-6) is -6
即使它们在内部是“不同的对象”,也始终为真;它还允许您配置是否启用此整数缓存,甚至设置下限和上限。但一般来说,从不同来源检索的对象不会相同。如果您想比较相等性,只需使用==
。
解决方案 2:
Python 在解释器中存储 -5 - 256 范围内的整数:它有一个整数对象池,这些整数从该池中返回。这就是为什么这些对象是相同的:(0-5)
但-5
不是(0-6)
和,-6
因为它们是当场创建的。
这是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
) 将位于不同的内存位置(然后is
不会返回True
)。请注意,257
上面的源代码中的 是针对正整数的,因此 是0 - 256
(包括在内)。
(来源)
解决方案 3:
这不是一个错误。is
不是一个平等测试。==
将给出预期的结果。
这种行为的技术原因是 Python 实现可以自由地将相同常量值的不同实例视为相同对象或不同对象。您使用的 Python 实现选择让某些小常量共享同一个对象以节省内存。您不能指望这种行为在各个版本之间或不同的 Python 实现之间是相同的。
解决方案 4:
发生这种情况的原因是 CPython 缓存了一些小整数和小字符串,并赋予该对象的每个实例相同的id()
。
(0-5)
和-5
的值相同,但对于和 来说id()
,这并不成立0-6
`-6`
>>> id((0-6))
12064324
>>> id((-6))
12064276
>>> id((0-5))
10022392
>>> id((-5))
10022392
对于字符串也类似:
>>> x = 'abc'
>>> y = 'abc'
>>> x is y
True
>>> x = 'a little big string'
>>> y = 'a little big string'
>>> x is y
False
有关字符串缓存的更多详细信息,请阅读:is
比较字符串与空格时,运算符的行为有所不同
扫码咨询,免费领取项目管理大礼包!