当python添加小整数时,幕后会发生什么?
我最近在玩弄当python添加小整数时,幕后会发生什么?,python,integer,cpython,Python,Integer,Cpython,我最近在玩弄id,意识到(c?)Python做了一些非常明智的事情:它确保小int始终具有相同的id >>> a, b, c, d, e = 1, 2, 3, 4, 5 >>> f, g, h, i, j = 1, 2, 3, 4, 5 >>> [id(x) == id(y) for x, y in zip([a, b, c, d, e], [f, g, h, i, j])] [True, True, True, True, True] 但
id
,意识到(c?)Python做了一些非常明智的事情:它确保小int始终具有相同的id
>>> a, b, c, d, e = 1, 2, 3, 4, 5
>>> f, g, h, i, j = 1, 2, 3, 4, 5
>>> [id(x) == id(y) for x, y in zip([a, b, c, d, e], [f, g, h, i, j])]
[True, True, True, True, True]
但我突然想到,数学运算的结果是否也是如此。结果是:
>>> nines = [(x + y, 9) for x, y in enumerate(reversed(range(10)))]
>>> [id(x) == id(y) for x, y in nines]
[True, True, True, True, True, True, True, True, True, True]
似乎它在n=257时开始失败
>>> a, b = 200 + 56, 256
>>> id(a) == id(b)
True
>>> a, b = 200 + 57, 257
>>> id(a) == id(b)
False
但有时,即使数字更大,它仍然有效:
>>> [id(2 * x + y) == id(300 + x) for x, y in enumerate(reversed(range(301)))][:10]
[True, True, True, True, True, True, True, True, True, True]
这是怎么回事?python是如何做到这一点的?AFAIK,id与参数的大小无关。它必须返回一个生命周期唯一标识符,如果两个不同的参数不同时存在,它可以为它们返回相同的结果。Python以一定的数字保存一个
int
对象池。当您在该范围内创建一个时,实际上会得到对先前存在的一个的引用。我怀疑这是出于优化的原因
对于超出该池范围的数字,无论何时尝试创建一个新对象,都会返回一个新对象
$ python
Python 3.2 (r32:88445, Apr 15 2011, 11:09:05)
[GCC 4.5.2 20110127 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 300
>>> id(x)
140570345270544
>>> id(100+200)
140570372179568
>>> id(x*2)
140570345270512
>>> id(600)
140570345270576
PyObject*PyInt_FromLong(long-ival)
返回值:新引用。创建一个
值为的新整数对象
伊瓦尔
当前的实现保持了
所有对象的整数对象数组
如果选择-5和256之间的整数
在指定的范围内创建一个int
事实上,只需要回一个参考
现有对象。因此它应该是
可以更改1的值。我
怀疑Python在中的行为
此案例未定义。:-)
强调我的你陷入了一个不寻常的陷阱:
id(2 * x + y) == id(300 + x)
这两个表达式2*x+y
和300+x
没有重叠的生存期。这意味着Python可以计算左侧,获取其id,然后在计算右侧之前释放整数。当CPython释放一个整数时,它会将其放在一个释放的整数列表中,然后在下次需要时将其重新用于另一个整数。因此,即使计算结果非常不同,您的ID也会匹配:
>>> x, y = 100, 40000
>>> id(2 * x + y) == id(300 + x)
True
>>> 2 * x + y, 300 + x
(40200, 400)
从文档:返回对象的“标识”。这是一个整数(或长整数),保证该对象在其生存期内唯一且不变。两个生命周期不重叠的对象可能具有相同的id()值。@Daenyth:请指定不正确的内容。呃,为什么删除注释而不解释它呢?一个(或部分或全部)python实现为某些少量整数保留一个数组的事实并不影响id()的工作方式。谁知道在其他或未来的实现中会不会是这样呢?我们不应该依赖于实现细节,而应该依赖于文档化的API来避免不好的意外。API声明了唯一性和一致性或不重叠的对象,没有其他内容。对于int的某些值,它会产生相同的输出,这很好,但这只是偶然的(由于您正在使用的当前实现)。再看看投票结果,我不知道为什么会有这么多人投了反对票。这里有两种行为,第一种是(实现定义的)特定整数对象的缓存,第二种是重用ID的可能性。Hyperboreus(AFAIU)正确地指出,在两个不同的对象上看到
id()
的相同结果,在对象具有非重叠生命期的情况下,这似乎毫无意义。邓肯的回答基本上就是这么说的,尽管无可否认,措辞没有那么清晰。这不是重点,每个人都有权在他们认为合适的时候这样做。重要的不是将代码基于随意的实现行为,而是基于文档化的API。顺便说一句,这是一个非常有趣的问题,有很多有趣的答案和评论。当数字较大时会发生什么?有时ID还是一样的。它是在做散列查找还是什么?@jsau:我编辑了我的答案以包含它。@Daenyth,是的,但有时它不是一个新对象;正如我的示例所示,有时2*x+y
返回与300+x
相同的对象。还是我误解了id
的作用?@jsau:我没看到。我不能确定在这种情况下会发生什么,但我确实发布了一个示例,支持您重新获得一个新对象id()
返回对象的唯一标识符,在cpython中,该标识符是对象在内存中的地址。如果id指向的对象被垃圾回收,则id将被重用。所以你不能把id作为伪对象密钥,它们可能会在以后指向不同的东西。好的,这是有道理的。谢谢因此,如果您上面所说的是真的,那么就有一种感觉,python int是可变的(只有在被垃圾收集之后)。