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 | 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 integer 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 instantiate 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, not cached.
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
are also dependant on the scope it is being executed in (beyond the span 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:
[7]
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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…