Python浮点数内存寻址行为:Spyder不同场景下id结果差异问题
现象核心成因
这个表现和float的不可变属性没有冲突,本质是Python解释器的常量折叠优化规则,在Spyder两种运行模式下触发条件不同导致的,和可变/不可变类型的特征没有关系:
- 整脚本运行场景(Spyder编辑器直接运行全量代码)
Python编译完整脚本文件时,会做全局级别的常量优化:对于代码中所有编译期就能确定值的不可变字面量(包括你代码里的1000.浮点数),只要值相等就会被合并成同一个内存对象,不会重复创建。
这种优化是安全的——正因为float是不可变类型,不存在修改一个变量就联动改动其他同值变量的风险,所以解释器才敢做这种复用。因此脚本里赋值给a的1000.、赋值给b的1000.、print语句里直接写的1000.字面量,全指向同一个常量对象,id自然完全相同。 - 控制台逐行执行场景
Spyder内置的IPython控制台是逐行/逐单元编译执行的:每提交一行代码,解释器只会单独编译当前输入行的内容,不会关联之前执行过的代码做全局优化。
逐行输入a=1000.时,解释器创建一个值为1000.的float对象绑定给a;输入下一行b=1000.时,因为编译范围只覆盖当前行,感知不到之前已经创建过同值的float对象,就会新生成一个1000.的对象绑定给b,两个变量的id自然不一致。后续print语句里的1000.是当前行编译时生成的临时对象,用完就会被回收,id也不会和前两个变量重合。
认知误区澄清
很多人会把“同值变量id是否相同”当成判断可变/不可变类型的标准,这个认知是错的:
判断类型可变性的唯一标准是对象创建后是否支持原地修改值。float对象创建后没有任何方法可以原地修改它的数值,所有对float变量的重新赋值本质都是让变量指向新的对象,因此它是严格的不可变类型。同值对象的id复用只是解释器做的性能优化,不是可变类型的特征。
测试代码
a = 1000. b = 1000. print('id of a=' + str(id(a))) print('id of b=' + str(id(b))) print('id of 1000.=' + str(id(1000.)))
内容的提问来源于stack exchange,提问作者Kernel
相关产品推荐
相关产品推荐

