Python 2.7.x/3.6.x中相同float值的不同变量为何id()相同?
为什么这些浮点数对象的ID会相同?
这是个非常典型的Python编译优化问题,咱们结合你的测试代码和运行结果来拆解背后的机制:
首先看你运行的测试代码:
f1 = 2.0 f2 = 2.0 print (id(f1), id(f2), id(f1) == id(f2)) f1 = 2.0 f2 = 2.00 print (id(f1), id(f2), id(f1) == id(f2)) f1 = 2.0 f2 = 2.0 + 0 print (id(f1), id(f2), id(f1) == id(f2))
不同Python版本的运行结果都呈现出一致规律:前两次打印的id相同,第三次不同。核心原因是编译时常量折叠和运行时计算的区别:
编译时常量折叠:字面量浮点数的合并
Python的字节码编译器在处理代码时,会对直接写死的浮点数字面量做优化:如果两个字面量在编译阶段就能确定数值完全相等(比如2.0和2.00,本质是同一个值),编译器会让它们指向同一个内存对象,避免重复创建相同的浮点数实例。这就是前两个测试用例里f1和f2的id完全相同的原因。运行时计算:无法提前优化的表达式
第三个用例里的2.0 + 0是需要程序运行时才能计算的表达式,虽然结果和2.0完全一致,但Python编译器不会在编译阶段提前计算这个表达式的结果(这类跨运算的逻辑不在常量折叠的规则范围内)。所以程序运行到这一行时,会新创建一个浮点数对象存储计算结果,导致f2的id和f1不同。
和整数缓存机制的区别
你提到的整数-5到256缓存机制,和浮点数的这个优化有本质不同:
- 整数缓存是解释器层面的全局对象池,不管是字面量还是运行时计算出的整数,只要在
-5到256范围内,都会复用同一个对象; - 而浮点数的优化只是编译阶段的字面量合并,仅针对直接书写的字面量,运行时计算出的浮点数(哪怕数值和字面量一致)都会创建新对象,也没有固定的范围限制。
另外要注意:这种优化是CPython的实现细节,其他Python解释器(比如PyPy)可能有不同处理方式,但你的测试结果在多个CPython版本里一致,说明这个行为是稳定的。
内容的提问来源于stack exchange,提问作者V. E.
相关产品推荐
相关产品推荐

