Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

float() object id creation order

float(1.0) is float(1.0) #True
float(1) is float(1) #False

I've isolated the float() oddity here to the object creation order, because

x1 = float(1)
x2 = float(1)
x1 is x2 #False
id(x1) == id(x2) #False
y1 = float(1.0)
y2 = float(1.0)
y1 is y2 #True
id(y1) == id(y2) #True

Note: I've done checks on the precision of the floats and it is not the reason why this is happening.

I wish to understand why and how is Python deciding to create float objects. Why is float(1.0) pointing to the same object while float(1) points to 2 different objects when either are created twice?

Also, for further reference:

float(1) is float(1) #False
id(float(1)) == id(float(1)) #True
float(1.0) is float(1.0) #True
id(float(1.0)) == id(float(1.0)) #True
like image 731
ycx Avatar asked Dec 12 '18 18:12

ycx


People also ask

What is float object in Python?

View More. Float() is a method that returns a floating-point number for a provided number or string. Float() returns the value based on the argument or parameter value that is being passed to it. If no value or blank parameter is passed, it will return the values 0.0 as the floating-point output.

How do you find the ID of an object in Python?

Every Python object is represented in C by a pointer to a PyObject struct. Because id(x) is just the memory address of this struct, we can retrieve the Python object just by treating x as a pointer to a PyObject , then calling Py_INCREF to tell the garbage collector that we're creating a new reference to the object.


1 Answers

>>> 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?).

like image 164
Jean-François Fabre Avatar answered Sep 20 '22 10:09

Jean-François Fabre