0

So Python 3.6.2 has some weird behavior with their assignment of id's for integer values.

For any integer value in the range [-5, 256], any variable assigned a given value will also be assigned the same ID as any other variable with the same value. This effect can be seen below.

>>> a, b = -5, -5
>>> id(a), id(b)
(1355597296, 1355597296)
>>> a, b = -6, -6
>>> id(a), id(b)
(2781041259312, 2781041260912)

In fact, to see the ID pairs in action, you can just run this simple program that prints out the number and id in the range that I'm talking about...

for val in range(-6, 258):
    print(format(val, ' 4d'), ':', format(id(val), '11x'))

If you add some other variables with values outside this range, you will see the boundary condition (i.e. -6 and 257) values id's change within the python interpreter, but never the values here.

This means (at least to me) that Python has taken the liberty to hardcode the addresses of variables that hold values in a seemingly arbitrary range of numbers.

In practice, this can be a little dangerous for a beginning Python learner: since the ID's assigned are the same within what is a a normal range of operation for beginners, they may be inclined to use logic that might get them in trouble, even though it seemingly works, and makes sense...

One possible (though a bit odd) problem might be printing an incrementing number:

a = 0
b = 10
while a is not b:
    a = a + 1
    print(a)

This logic, though not in the standard Pythonic way, works and is fine as long as b is in the range of statically defined numbers [-5. 256]

However, as soon as b is raised out of this range, we see the same strange behavior. In this case, it actually throws the code into an infinite loop.

I know that using 'is' to compare values is really not a good idea, but this produces inconsistent results when using the 'is' operator, and it is not immediately obvious to someone new to the language, and it would be especially confusing for new programmers that mistakenly used this method.

So my question is...
a) Why (was Python written to behave this way), and
b) Should it be changed?

p.s. In order to properly demonstrate the range in a usable script, I had to do some odd tweaks that really are improper code. However, I still hold my argument, since my method would not show any results if this odd glitch didn't exist.

for val in range(-6, 300):
    a = int(float(val))
    b = int(float(val))
    print(format(a, ' 4d'), format(id(a), '11x'), ':',format(b, ' 4d'), format(id(b), '11x'), ':', a is b)
    val = val + 1

The float(int(val)) is necessary to force Python to give each value a new address/id rather than the pointer to the object that it is accessing.

David Culbreth
  • 2,610
  • 16
  • 26
  • This is an old topic See: https://stackoverflow.com/questions/15171695/whats-with-the-integer-cache-inside-python – mementum Dec 26 '17 at 19:08

1 Answers1

0

This is documented behavior of Python:

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. source

It helps to save memory and to make operations a bit faster. It is implementation-specific. For example, IronPython has a range between -1000 and 1000 in which it it re-uses integers.

Mike Müller
  • 82,630
  • 20
  • 166
  • 161