G&#252;nther Jena - 2 months ago 5x
Python Question

# `is` operator gives unexpected results on floats

I came across a confusing problem when unit testing a module. The module is actually casting values and I want to compare this values.

There is a difference in comparison with

`==`
and
`is`
(partly I'm beware of the difference)

``````>>> 0.0 is 0.0
True   # as expected
>>> float(0.0) is 0.0
True   # as expected
``````

As expected till now, but here is my "problem":

``````>>> float(0) is 0.0
False
>>> float(0) is float(0)
False
``````

Why? At least the last one is really confusing to me. The internal representation of
`float(0)`
and
`float(0.0)`
should be equal. Comparison with
`==`
is working as expected.

This has to do with how `is` works. It checks for references instead of value. It returns `True` if either argument is assigned to the same object.

In this case, they are different instances; `float(0)` and `float(0)` have the same value, but are distinct entities as far as Python is concerned. CPython implementation also caches integers as singleton objects in this range -> [x ≥ -5 | x ≤ 256 ]:

``````>>> 0.0 is 0.0
True
>>> float(0) is float(0)  # Not the same reference, unique instances.
False
``````

In this example we can demonstrate the caching principle:

``````>>> a = 256
>>> b = 256
>>> a is b
True
>>> a = 257
>>> b = 257
>>> a is b
False
``````

Now, if floats are passed to `float()`, the float literal is simply returned (short-circuited), as in the same reference is used, as there's no need to make a new float from an existing float:

``````>>> 0.0 is 0.0
True
>>> float(0.0) is float(0.0)
True
``````

This can be demonstrated further by using `int()` also:

``````>>> int(256.0) is int(256.0)  # Same reference, cached.
True
>>> int(257.0) is int(257.0)  # Different references are returned.
False
>>> 257 is 257  # Same reference.
True
>>> 257.0 is 257.0  # Same reference. As @Martijn Pieters pointed out.
True
``````

However, the results of `is` also depend on the scope it is being executed in (beyond the scope of this question/explanation), please refer to user: @Jim's fantastic explanation on code objects. Even python's doc includes a section on this behavior:

5.9 Comparisons

Due to automatic garbage-collection, free lists, and the dynamic nature of descriptors, you may notice seemingly unusual behaviour in certain uses of the `is` operator, like those involving comparisons between instance methods, or constants. Check their documentation for more info.