Python序列切片的id()返回值疑问:内存地址与重复身份解析
列表切片的id()返回值困惑解析
问题背景
根据Python 3.11.0文档《3. Data model》的CPython实现细节:
CPython实现细节:在CPython中,id(x)是x存储的内存地址。
测试列表单个元素的id时,结果符合预期:
>>> l = list(range(10)) >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> l[3] 3 >>> l[7] 7 >>> id(l) 1931973192256 >>> id(l[3]) 1931941276016 >>> id(l[7]) 1931941276144
列表对象与单个元素的内存地址各不相同,这符合预期。但切片操作的id结果却出现了反常现象:
>>> l[2:] [2, 3, 4, 5, 6, 7, 8, 9] >>> l[5:] [5, 6, 7, 8, 9] >>> l[3:9] [3, 4, 5, 6, 7, 8] >>> l[:-6] [0, 1, 2, 3] >>> id(l[2:]) 2813785568448 >>> id(l[5:]) 2813784049664 >>> id(l[3:9]) 2813784049664 >>> id(l[:-6]) 2813784049664 >>> id(l[2:]) 2813784049664
首次切片的id与后续所有切片(包括重复执行首次切片操作)的id完全相同,无论切片内容如何。
疑问
- 对列表切片时,
id()返回的具体是哪个对象的内存地址? - 为何首次与第二次切片的id不同,但后续切片(含首次切片)的id均相同?
核心解析
1. 切片返回的是新创建的列表对象
列表的切片操作l[a:b]每次都会生成一个全新的列表对象,这个新列表包含原列表对应范围元素的引用。id()返回的就是这个新创建的列表对象的内存地址。
2. 临时对象的内存复用机制
出现id重复的本质是CPython的临时对象内存复用策略:
- 在交互式环境中,执行
id(l[2:])时,第一个切片生成的新列表是临时对象——id()执行完毕后,这个对象没有任何变量引用它,会被Python的垃圾回收机制标记为可回收。 - 后续执行切片操作时,新创建的列表会复用之前被回收的临时对象的内存空间,因此它们的
id()会和之前的临时对象一致。 - 首次切片的id与后续不同,是因为此时没有可复用的内存空间,Python需要分配一块新内存;当第一次切片的对象被回收后,后续切片就可以复用这块内存,所以id全部相同。
补充说明
这种现象在交互式环境中更容易观察到。如果在脚本中用变量保存切片结果(比如slice1 = l[2:]),该对象会被持续引用,内存不会被回收,后续切片的id就会与它不同。
内容的提问来源于stack exchange,提问作者bixb0012
相关产品推荐
相关产品推荐

