我注意到了某些序列类型的切片的“标识”,即id()
返回的值,我无法理解。我看到它带有列表和字符串,这使我认为它与CPython中序列或切片的实现有关。
如3. Data model - Python 3.11.0 documentation中所述:
CPython实现详细信息:对于CPython,id(x)是存储x的内存地址。
>>> 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
到目前为止,没有什么异常,因为我希望看到列表对象的内存地址与从列表返回的单个元素的内存地址不同。然而,当查看列表的切片时,内存地址对我来说没有意义:
>>> 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()
返回的内存地址到底是什么?接下来,为什么第一个和第二个切片的标识不同,而后面的切片是相同的,包括第一个切片?
1条答案
按热度按时间brqmpdu11#
这种行为是由Cpython优化引起的。
对list always creates a new list进行切片。由于分配和释放列表对象是一个开销很大的操作,python解释器会跟踪
free_list
,它是指向PyListObject
的指针数组。所以当你请求一个新的列表时(记住分片也会创建一个新的列表),它会从这个空闲列表中得到服务(如果空闲列表可用)。
因为你要立即丢弃list对象,python解释器调用
list_dealloc
,它将恢复这个free_list
。下次进行分片时,实际上是从
free_list
获取对同一列表对象的引用。