What happens behind the scenes when python adds small ints? [duplicate]

孤街浪徒 提交于 2019-11-26 21:08:51

问题


I was fiddling around with id recently and realized that (c?)Python does something quite sensible: it ensures that small ints always have the same 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]

But then it occurred to me to wonder whether the same is true for the results of mathematical operations. Turns out it is:

>>> 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]

Seems like it starts failing at n=257...

>>> a, b = 200 + 56, 256
>>> id(a) == id(b)
True
>>> a, b = 200 + 57, 257
>>> id(a) == id(b)
False

But sometimes it still works even with larger numbers:

>>> [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]

What's going on here? How does python do this?


回答1:


Python keeps a pool of int objects in certain numbers. When you create one in that range, you actually get a reference to the pre-existing one. I suspect this is for optimization reasons.

For numbers outside the range of that pool, you appear to get back a new object whenever you try to make one.

$ 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

Source

PyObject* PyInt_FromLong(long ival) Return value: New reference. Create a new integer object with a value of ival.

The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you actually just get back a reference to the existing object. So it should be possible to change the value of 1. I suspect the behaviour of Python in this case is undefined. :-)

emphasis mine




回答2:


You've fallen into a not uncommon trap:

id(2 * x + y) == id(300 + x)

The two expressions 2 * x + y and 300 + x don't have overlapping lifetimes. That means that Python can calculate the left hand side, take its id, and then free the integer before it calculates the right hand side. When CPython frees an integer it puts it on a list of freed integers and then re-uses it for a different integer the next time it needs one. So your ids match even when the result of the calculations are very different:

>>> x, y = 100, 40000
>>> id(2 * x + y) == id(300 + x)
True
>>> 2 * x + y, 300 + x
(40200, 400)



回答3:


AFAIK, id has nothing to do with the size of the parameter. It MUST return a life-time unique identifier, and it CAN return the same result for two different parameters, if they do not exist concurrently.



来源:https://stackoverflow.com/questions/6101379/what-happens-behind-the-scenes-when-python-adds-small-ints

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!