在Python里写a = 3.14时,你创建的其实是个C语言结构体。这个结构体里藏着两个关键数字:一个计数器记录有多少变量指向它,一个指针说明"我是什么类型"。
这就是CPython的核心设计——一切皆对象。连"类"本身也是对象。
CPython源码中,所有对象的共同基础是PyObject结构体,定义在Include/object.h。它只有两个字段:ob_refcnt(引用计数)和ob_type(类型指针)。前者决定对象何时被垃圾回收,后者决定对象能做什么。
变长对象(如列表、字符串)在此基础上扩展为PyVarObject,增加ob_size字段记录元素个数。固定长度对象(如浮点数)直接复用PyObject头部,后面紧跟具体数据。
以浮点数为例:PyFloatObject包含PyObject_HEAD宏展开后的头部,加上一个double类型的ob_fval。当你写x = 3.14,内存中就是一个引用计数为1、类型指向PyFloat_Type、值为3.14的结构体。
列表更复杂。PyListObject用PyObject_VAR_HEAD宏获得变长头部,包含ob_refcnt、ob_type、ob_size三个字段。此外它还有ob_item指针数组(存储元素地址)和allocated字段记录当前分配的内存槽位数——后者通常大于实际元素数,为追加操作预留空间。
这种设计解释了Python的两个经典特性:一是变量赋值只是指针拷贝(y = x让ob_refcnt加1),二是列表的均摊O(1)追加(allocated预留机制)。
源码中还有个细节:_PyObject_HEAD_EXTRA宏。在调试模式下,它会在头部插入两个指针,把所有堆对象串成双向链表。这是CPython的内存调试工具,正式发行版中为空。
从C视角看,Python的"动态类型"不过是每次操作前查一下ob_type指针。这种统一的对象模型让Python的C扩展开发有章可循——无论你封装的是神经网络库还是硬件驱动,都遵循同样的结构体约定。
热门跟贴