float() object id creation order float() object id creation order python-3.x python-3.x

float() object id creation order


>>> float(1.0) is float(1.0)True

That's because float returns the object itself because it's already a float (same for strings BTW Should I avoid converting to a string if a value is already a string?).

Checking the source code to confirm (with added comments):

static PyObject *float_float(PyObject *v){    if (PyFloat_CheckExact(v))   // if v is already a float, just increase reference and return the same object        Py_INCREF(v);    else        // else create a new float object using the input value        v = PyFloat_FromDouble(((PyFloatObject *)v)->ob_fval);    return v;}

And the reference on literal 1.0 is probably shared when compiled (that's implementation defined, and that's the only explanation I can think of, Dunes answer explains it much better), so it's the same as 1.0 is 1.0.

>>> float(1) is float(1)False

Python has to create floating point objects for each side, so it's different. There isn't any floating point interning like integers.

And last fun part:

>>> id(float(1)) == id(float(2))True

because the float object is garbage collected after id has been called, so id is reused, even if the literal values are different as the above example shows (as exposed in Unnamed Python objects have the same id or Why is the id of a Python class not unique when called quickly?).


1.0 is literal syntax for a float object, and so the interpreter has to create a float object that it can pass to float. Since floats are immutable, the float function can just return the object unchanged. On the other hand 1 is literal syntax for an integer. As such, the float function must create a new float object. Within the same block of code the interpreter sometimes (not always) is able to identify that two literals for immutable objects are identical then it is able to cache that object and reuse for other references. This is an internal memory optimisation and should not be relied upon.

Thus:

def f():    x = 1.0    y = float(1.0)    z = float(x)    assert x is y # x and y are the same object    assert x is z # z is also the same as both x and yf()

But:

def f():    return 1.0def g():    return 1.0assert f() is not g() # The interpreter was not able to detect it could reuse the same object

Long story short, sometimes numbers in python that are equal might also be the exact same object, but that this is not guaranteed.