代码之家  ›  专栏  ›  技术社区  ›  ycx

float()对象ID创建顺序

  •  6
  • ycx  · 技术社区  · 7 年前
    float(1.0) is float(1.0) #True
    float(1) is float(1) #False
    

    我将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
    

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

    我想了解为什么以及如何由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
    
    2 回复  |  直到 7 年前
        1
  •  6
  •   Jean-François Fabre    7 年前
    >>> float(1.0) is float(1.0)
    True
    

    那是因为 float 返回对象本身,因为它已经是 浮动 (字符串btw相同 Should I avoid converting to a string if a value is already a string? )

    检查 source code 确认(添加注释):

    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;
    }
    

    和字面上的引用 1.0 可能是编译时共享的(这是实现的定义,这是我能想到的唯一解释, Dunes answer 解释得更好),所以它与 1.0 is 1.0 .

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

    python必须为每一侧创建浮点对象,所以它是不同的。没有任何像整数那样的浮点插入。

    最后一个有趣的部分:

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

    因为 浮动 对象在之后被垃圾收集 id 已被调用,因此ID为 再利用 ,即使文本值为 不同的 如上述示例所示(如 Unnamed Python objects have the same id Why is the id of a Python class not unique when called quickly? )

        2
  •  2
  •   Dunes    7 年前

    1.0 是float对象的文本语法,因此解释器必须创建一个float对象,它可以传递给 float . 因为浮点数是不可变的,所以 浮动 函数只能返回未更改的对象。另一方面 1 是整数的文本语法。这样, 浮动 函数必须创建一个新的float对象。在同一个代码块中,解释器 有时 (不总是)能够识别不可变对象的两个文本是相同的,然后它能够缓存该对象并重新用于其他引用。这是一种内存优化,不应依赖。

    因此:

    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 y
    f()
    

    但是:

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

    长话短说,有时在python中数字相等 可以 同样是相同的对象,但这是不保证的。