我注意到了一些具有“身份”的东西,即由id()返回的某些序列类型的切片的值,这些片段是我根本无法理解的。我在列表和字符串中看到了它,这使我认为它与CPython中的序列或片的实现有关。
如3.数据模型- Python 3.11.0文档所涵盖的那样
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()返回内存地址到底是什么?而后续,为什么第一和第二片的身份不同,但之后的切片是相同的,包括第一片?
发布于 2022-11-16 08:00:30
这种行为是因为Cpython的优化。让我们从
>>> l[2:]切片一个列表总是创建一个新列表。。因为分配和释放列表对象是一项昂贵的操作,所以python解释器会跟踪PyListObject。
/* Empty list reuse scheme to save calls to malloc and free */
#ifndef PyList_MAXFREELIST
# define PyList_MAXFREELIST 80
#endif
struct _Py_list_state {
#if PyList_MAXFREELIST > 0
PyListObject *free_list[PyList_MAXFREELIST];
int numfree;
#endif
};所以当你要求一个新的名单(记住切片也创建了一个新的列表)是从此免费列表中送达(如果可用的话)。
if (PyList_MAXFREELIST && state->numfree) {
state->numfree--;
op = state->free_list[state->numfree];
OBJECT_STAT_INC(from_freelist);
_Py_NewReference((PyObject *)op);
}由于您要立即丢弃list对象,所以python解释器调用list_dealloc,这将恢复这个free_list。
if (state->numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) {
state->free_list[state->numfree++] = op;
OBJECT_STAT_INC(to_freelist);
}当您下次进行切片时,实际上是从free_list获得对同一个list对象的引用。
https://stackoverflow.com/questions/74451312
复制相似问题