0

My understanding of variable assignment in Python is that when you do a = 1, the interpreter allocates some memory, stores the number 1 and then a is a reference to that number. Why does the following happen:

a = 1
b = 1
a is b
#True

On the other hand:

a = 1.
b = 1.
a is b
#False

What is going on? I expected both statements to evaluate to False

Alex
  • 19,533
  • 37
  • 126
  • 195

1 Answers1

2

The interpreter doesn't have to allocate some memory and create a 1 value if it already has one lying around it can use. As long as the value is immutable, that is, but ints are immutable in Python.

CPython happens to pre-create values for a whole range of small ints. The exact range has changed a couple times over the decades (and is configurable at build time), but obviously any collection of "small ints" is going to include 1.


This pre-creation doesn't happen, in CPython, for floats, or large ints, or non-empty tuples or strings—but they can end up identical anyway. In particular, if the compiler sees the same value twice in the same compilation unit, for a type it knows to be immutable, it can merge them. You generally only see this in module constants, not at the interactive interpreter, because interactively, each statement is a separate compilation unit. But:

>>> a = 1.0
>>> b = 1.0
>>> a is b
False
>>> c, d = 1.0, 1.0
>>> c is d
True

A different Python implementation might do things differently. (And there's one other trick just within CPython, string interning, which can be even more complicated to guess the outcome of in 3.4 and later.)


The takeaway is:

  • Never assume that two separately-created but equal-valued immutables are identical.
  • But never assume they aren't identical, either.

If you find yourself using is with an int, string, or any other open-ended immutable type, you're probably doing something wrong. (Or intentionally exploring how your interpreter works, of course.)

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • not clear on this: "The interpreter doesn't have to allocate some memory and create a 1 value if it already has one lying around it can use." By that logic shouldn't the same thing happen with floats or does this wade into some machine precision stuff? – Alex Mar 25 '18 at 02:47
  • 2
    @Alex: It doesn't have to create a new object, but that doesn't mean it won't. Python makes no promises regarding whether it will or won't. – user2357112 Mar 25 '18 at 02:49
  • 1
    @Alex The same thing _can_ happen with floats. The interpreter doesn't pre-create any float values—but if you, e.g., use the some float constant twice at the top level of the same module, it can merge them into the same value at compile time, and it can also do that for tuples, or strings, or non-small ints. – abarnert Mar 25 '18 at 02:50
  • 1
    @Alex The reason you don't see it with floats on the interactive interpreter is that CPython's constant merging is done by the compiler, not the interpreter, and only within compilation units, and at the interactive interpreter, each statement is its own compilation unit. (Except for the special case of string interning, which _is_ done by the interpreter…) – abarnert Mar 25 '18 at 02:53
  • interesting. makes sense. thanks for the help – Alex Mar 25 '18 at 02:55