42、True、len 本身)。int, double, boolean 等 非对象 的原始类型(primitive)。Object[],必须用装箱类(Integer, Double)才能享受对象待遇。实现层面
[1,2]、函数 len、类 int 本身……PyObject(含引用计数 + 类型指针),后面爱加多少字段再加。PyObject * 安全地传递。PyObject 里?PyObject 里?type(x) 必须能在运行时回答。ob_type 指针塞进头部,解释器就能:ob_type)ob_type->tp_methods 等)obj->ob_type->tp_repr(obj))PyObject 就是 CPython 的“对象通行证”:少了它,解释器连怎么分配、怎么回收、怎么找方法都无从下手。CPython 源码中,PyObject * 是一个指向对象结构体的指针,它是 Python 所有对象的“最小公共祖先”:
typedef struct _object {
Py_ssize_t ob_refcnt; // 引用计数
struct _typeobject *ob_type; // 类型指针
} PyObject; 外只暴露 PyObject 这个名字,隐藏底层 struct _object,struct _object 是结构体的标签名(tag)只在结构体内部可见
PyObject 是类型别名(typedef 名),对外使用。 使用时直接写 PyObject obj;不用写struct _object objob_refcnt:引用计数,用于垃圾回收。ob_type:指向类型对象的指针(也就是你熟悉的 Python 的 type(obj))。继承 PyObject 的对象长啥样?
比如一个自定义对象: c typedef struct { PyObject_HEAD // 展开后是 PyObject 的成员 int my_value; } MyObject;
MyObject 的第一个成员就是 PyObject,所以你可以把 MyObject* 当作 PyObject* 来用。在 C 语言里谈“继承”,本质上就是把父结构体完整地嵌(放)在子结构体的最前面,除此之外没有别的魔法—没有 extends,没有自动向上转型,也没有虚函数表,全靠“内存布局”+“强制类型转换”来手动实现。C 语言本身并没有“继承、多态”这两个语法概念
PyObject(或变长版 PyVarObject)对象内存布局 = [ PyObject 头部 | 子类私有字段 ]
PyObject *,不是二级指针PyDictObject,键是字符串,值是 PyObject *PyDictObject,3.11 起有了更紧凑的 PyLocalsArray,但同样存的是 PyObject *__dict__ 同理,值都是 8 字节(64 位机)指针。locals["lst"] -----> PyListObject 在堆上的地址
Python 层: lst = [1, 2, 3] C 层: locals (PyDictObject) +---------+ | key | value (PyObject *) | "lst" | 0x7f8e3c2a1b00 ----------> [PyObject_HEAD | ob_size=3 | *ob_item] +---------+ 没有 PyObject **; 没有“二级指针”; 变量名 "lst" 只是字典键,指向唯一的 PyListObject。 “所有对象都继承自 PyObject,变量名只是给指向堆对象的指针贴的标签。PyListObject里面又是一块连续的“一级指针”数组,专门用来存放列表元素