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
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.
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.
>>> 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?).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With