Python中连续调用list.copy()传入print时ID相同的原因与疑问
问题解答
1. 触发原因:临时对象的内存复用
这种现象本质是Python垃圾回收机制对无引用临时对象的内存复用优化:
- 执行
id(a.copy())时,a.copy()生成的列表副本是个临时对象——它没有被赋值给任何变量,也没有其他引用指向它。一旦id()获取完它的内存地址,这个对象就失去了所有引用,Python会立刻回收它占用的内存空间。 - 紧接着执行第二个
id(a.copy())时,新创建的列表副本会复用刚刚被释放的内存地址,因此两次输出的ID完全相同。
其他测试场景不会出现该现象的原因:
- 赋值给变量(
b, c = a.copy(), a.copy()):两个副本被变量持有引用,对象不会被立即回收,因此占用不同内存地址。 - 传入自定义函数:函数参数会持有对象的引用,两个副本在函数执行期间同时存在,ID自然不同。
a.copy() is a.copy():这个表达式会先计算左右两边的副本,两个对象会同时存在(因为要完成is比较),所以它们的内存地址不同,结果为False。
2. 潜在风险与其他复现方式
潜在bug可能性
正常编程场景下几乎不会引发bug:
- 这种内存复用仅发生在无引用的临时对象上,只要你将对象赋值给变量、存入容器或用其他方式持有引用,对象就不会被立即回收,ID会保持唯一。
- 只有当你错误地用
id()的结果作为对象的唯一标识(比如用ID做缓存键)时,才可能出现逻辑错误——不同对象可能在不同时间复用同一个内存地址。但Python中判断对象是否为同一个应该用is,判断值相等用==,用id()做判断本身就是不规范的写法。
其他复现方式
只要是在同一个表达式中创建两个无引用的临时对象,都可能出现ID相同的情况,比如:
# 两次创建空列表 print(id([]), id([])) # 两次调用list()生成副本 print(id(list([1,2,3])), id(list([1,2,3])))
内容的提问来源于stack exchange,提问作者botanich
相关产品推荐
相关产品推荐

