PyVarObject 的实际使用,cpython 的 PyObject 的可变长度子类型

Practical use of PyVarObject, the variable-length subtype of cpython’s PyObject

作为最近一直在研究 Python C-API 的人,我很好奇 PyVarObject,它是 the documentation says 的子类型PyObject 专门用于可变长度类型的定义——尽管需要注意的是:

This type does not often appear in the Python/C API

… 有大量记录在案的 support structures, slot hooks 和其他 API 专用于 PyVarObject 的细枝末节,以至于我真的很好奇是否有任何 Python-API 相关问题(但特别小众),它可以显着简化解决方案。

它主要用于不可变容器类型(例如 tuple and bytes)。这个想法是该类型可以在其末尾有一个包含其所有数据的数组。当它被分配时(使用 PyObject_NewVar 或类似的)额外的 space 被分配给它将包含的(不可变的)数据,这简化了内存管理并且可能通过只需要做一个来获得一点速度内存分配。因为大小在构建后永远不会改变,所以它可以采用这种快捷方式,而不必担心通过重新分配内存来使对它的引用无效。

稍微混淆一下 list is also a PyVarObject despite being mutable. However, it has an item size of 0,因此实际上在对象的末尾没有分配额外的 space。相反,它存储一个指向 PyObject* 数组的指针,单独分配(如果列表增长而不会使对列表的引用无效,则可以重新分配)。据推测,它被设为 PyVarObject 只是为了有一个 ob_size 字段。