Günther Jena Günther Jena - 4 months ago 18
Python Question

Why is in python float not actually a float (at least in some cases)?

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.

Answer

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 ], which is the first example returns True:

>>> 0.0 is 0.0
True
>>> float(0) is float(0)
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:

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