为何同一段Python代码在交互提示符与文件运行时id()断言结果不同?
问题解析:Python交互模式与脚本文件中id()行为差异的原因
核心原因是CPython在脚本文件和交互模式下的常量编译策略不同,导致相同字面量是否复用同一对象的逻辑有区别,和整数缓存机制无关。
1. 脚本文件中的行为:常量复用
当你在脚本文件中执行i = 12345; assert id(i) == id(12345)时,CPython的字节码编译器会进行常量折叠优化:
- 编译器会扫描整个脚本的常量,把所有值相同的字面量(比如这里的两个
12345)合并到同一个常量槽中。 - 执行时,
i被赋值为这个常量槽中的整数对象,id(12345)也是引用同一个对象,所以两者的id完全一致,断言不会触发错误。
你可以用dis模块验证字节码:
# 脚本文件list_and_int_1.py中添加以下代码 import dis dis.dis('i = 12345; assert id(i) == id(12345)')
运行后会看到,两次LOAD_CONST指令都使用了同一个索引(比如0),说明引用的是同一个常量对象。
2. 交互模式中的行为:常量不复用
而在交互模式下,CPython的编译策略更为保守:
- 即使是同一行代码中的相同字面量,编译器也不会将它们合并到同一个常量槽,而是会生成两个独立的常量项。
- 执行时,
i = 12345创建第一个整数对象并赋值给i,id(12345)则创建第二个全新的整数对象,两个对象的内存地址不同,所以id()返回值不一样,触发AssertionError。
同样用dis模块验证:
>>> import dis >>> dis.dis('i = 12345; assert id(i) == id(12345)')
输出会显示两次LOAD_CONST使用了不同的索引(比如0和1),说明引用的是两个不同的常量对象。
3. 关于id()文档的准确性
CPython文档中“id()返回对象内存地址,唯一且在对象生命周期内恒定”的描述是完全准确的:
- 在脚本模式下,两个
12345是同一个对象,它的id在生命周期内始终唯一且不变; - 在交互模式下,两个
12345是两个独立的对象,各自有唯一的id,只是它们的值相同而已。这完全符合文档的定义。
内容的提问来源于stack exchange,提问作者user7711283
相关产品推荐
相关产品推荐

