float()对象id创建顺序


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
>>> float(1.0) is float(1.0)
True

这是因为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;
}

在编译时,对字面1.0的引用可能是共享的(这是实现定义的,这是我能想到的唯一解释,Dunes答案解释得更好(,所以它与1.0 is 1.0相同。

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

Python必须为每一侧创建浮点对象,所以它是不同的。不存在任何像整数一样的浮点插值。

最后一个有趣的部分:

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

因为float对象是在调用id之后垃圾收集的,所以id被重用,即使文字值不同(如Unnamed Python对象具有相同的id或快速调用时Python类的id为什么不唯一?(。

1.0是浮点对象的字面语法,因此解释器必须创建一个可以传递给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中等于的数字也可能是完全相同的对象,但这并不能保证。

最新更新