我最近在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是如何做到的?
答案 0 :(得分:18)
你陷入了一个不常见的陷阱:
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)
答案 1 :(得分:17)
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) 返回值:新参考。创建一个 值为的新整数对象 IVAL。
当前实施保持一个 所有的整数对象数组 -5到256之间的整数,当你 在你的范围内创建一个int 实际上只是回来参考 现有的对象。应该如此 可以改变1的值 怀疑Python的行为 这种情况是未定义的。 : - )
强调我的
答案 2 :(得分:2)
AFAIK,id与参数的大小无关。它必须返回一个生命周期唯一标识符,如果它们不同时存在,它可以为两个不同的参数返回相同的结果。