float()对象id创建顺序

ycx*_*ycx 6 python floating-point python-3.x

float(1.0) is float(1.0) #True
float(1) is float(1) #False
Run Code Online (Sandbox Code Playgroud)

我已将float()奇怪性与此对象创建顺序隔离开来,因为

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
Run Code Online (Sandbox Code Playgroud)

注意:我已经检查了浮点数的精度,这不是发生这种情况的原因.

我想了解Python为何以及如何决定创建浮动对象.为什么float(1.0)指向同一个对象,而float(1)指向两个不同的对象,当它们被创建两次时?

另外,有待进一步参考:

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
Run Code Online (Sandbox Code Playgroud)

Jea*_*bre 6

>>> float(1.0) is float(1.0)
True
Run Code Online (Sandbox Code Playgroud)

那是因为float它已经是一个返回对象本身float(对于字符串BTW 是相同的,如果值已经是字符串,我应该避免转换为字符串吗?).

检查源代码以确认(添加注释):

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;
}
Run Code Online (Sandbox Code Playgroud)

文字的引用1.0可能在编译时被共享(这是实现定义的,这是我能想到的唯一解释,Dunes的答案更好地解释了它),所以它是相同的1.0 is 1.0.

>>> float(1) is float(1)
False
Run Code Online (Sandbox Code Playgroud)

Python必须为每一面创建浮点对象,所以它是不同的.没有任何像整数一样的浮点数.

最后一个有趣的部分:

>>> id(float(1)) == id(float(2))
True
Run Code Online (Sandbox Code Playgroud)

因为在float调用之后对象是垃圾收集的id,所以id被重用,即使文字值不同,如上例所示(在未命名的Python对象中公开具有相同的id为什么Python类的id不是唯一的什么时候快速打电话?)

  • 值得注意的是,对两个连续对象重用"id"是CPython的一个怪癖.它实际上保证在CPython中发生,但实际上保证*不会发生在我所知道的每个其他Python实现中. (2认同)