Python – Uncommon Behavior of IS Operator Explained

python

From some of the answers on Stackoverflow, I came to know that from -5 to 256 same memory location is referenced thus we get true for:

>>> a = 256
>>> a is 256
True

Now comes the twist (see this line before marking duplicate):

>>> a = 257
>>> a is 257 
False 

This is completely understood, but now if I do:

>>> a = 257; a is 257
True
>>> a = 12345; a is 12345
True

Why?

Best Answer

What you're seeing is an optimization in the compiler in CPython (which compiles your source code into the bytecode that the interpreter runs). Whenever the same immutable constant value is used in several different places within the a chunk of code that is being compiled in one step, the compiler will try to use a reference to same object for each place.

So if you do multiple assignments on the same line in an interactive session, you'll get two references to the same object, but you won't if you use two separate lines:

>>> x = 257; y = 257  # multiple statements on the same line are compiled in one step
>>> print(x is y)     # prints True
>>> x = 257
>>> y = 257
>>> print(x is y)     # prints False this time, since the assignments were compiled separately

Another place this optimization comes up is in the body of a function. The whole function body will be compiled together, so any constants used anywhere in the function can be combined, even if they're on separate lines:

def foo():
    x = 257
    y = 257
    return x is y  # this will always return True

While it's interesting to investigate optimizations like this one, you should never rely upon this behavior in your normal code. Different Python interpreters, and even different versions of CPython may do these optimizations differently or not at all. If your code depends on a specific optimization, it may be completely broken for somebody else who tries to run it on their own system.

As an example, the two assignments on the same line I show in my first code block above doesn't result in two references to the same object when I do it in the interactive shell inside Spyder (my preferred IDE). I have no idea why that specific situation doesn't work the same way it does in a conventional interactive shell, but the different behavior is my fault, since my code relies upon implementation-specific behavior.