float()对象ID的创建顺序

时间:2018-12-12 18:42:59

标签: python python-3.x floating-point

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对象。 为什么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 个答案:

答案 0 :(得分:6)

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

那是因为float返回对象本身,因为它已经是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}}。

1.0 is 1.0

Python必须为每一侧创建浮点对象,因此有所不同。没有像整数这样的浮点数实习。

最后一个有趣的部分:

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

因为>>> id(float(1)) == id(float(2)) True 对象是在调用float之后被垃圾回收的,所以即使字面值是不同的,id也被重用。如以上示例所示(在Unnamed Python objects have the same idWhy is the id of a Python class not unique when called quickly?中公开)。

答案 1 :(得分:2)

1.0是float对象的文字语法,因此解释器必须创建一个float对象,然后可以将其传递给float。由于浮点数是不可变的,因此float函数可以不变地返回对象。另一方面,1是整数的文字语法。这样,float函数必须创建一个新的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中等于可能的数字也是完全相同的对象,但这并不能保证。