As far as I know cpython implementation keeps the same object for some same values in order to save memory. For example when I create 2 strings with the value hello, cpython does not create 2 different PyObject:
>>> s1 = 'hello'
>>> s2 = 'hello'
>>> s1 is s2
True
I heard about it with name string interning. When I tried to check it with other python types I observed that almost all hashable (immutable) types are the same:
>>> int() is int()
True
>>> str() is str()
True
>>> frozenset() is frozenset()
True
>>> bool() is bool()
True
And almost all mutable types are the opposite (cpython creates a new PyObject even for the same values):
>>> list() is list()
False
>>> set() is set()
False
>>> dict() is dict()
False
And I think it's because we can have the same PyObject for immutable objects without having any problem.
My question arises when I see that the float type behave differently than other immutable types:
>>> float() is float()
False
Why is it different?