CPython

基于 cpython==3.12.4, 主要结合 微信公众号古明地觉cpython系列 作为参考

// Include/pytypedefs.h
typedef struct _object PyObject;

// Include/object.h

// 这个也就是 python 代码里的 object
// 简化后(主要是去掉了不必要的跨平台的宏, 仅考虑linux x86_64)
struct _object {
    union {
        Py_ssize_t ob_refcnt;  // Py_ssize_t 是指 64 位整数
        Py_UINT32_T ob_refcnt_split[2];
    };
    PyTypeObject *ob_type;
}

// 很多变长对象的实现会在 PyObject 的基础上增加一个属性
typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size;
} PyVarObject;

// 以下两个宏很常见
#define PyObject_HEAD PyObject ob_base;
#define PyObject_VAR_HEAD PyVarObject ob_base;

// 例如, python 中的浮点数的实现是用 double 来实现的
// Include/cpython/floatobject.h
typedef struct {
    PyObject_HEAD
    double ob_fval;
} PyFloatObject;

然后再看 PyTypeObject:

// Include/pytypedefs.h
typedef struct _typeobject PyTypeObject;

// Include/cpython/object.h
struct _typeobject {
    PyObject_VAR_HEAD
    const char *tp_name;
    // ...
}

// _pyObject_EXTRA_INIT 宏可忽略
#define PyObject_HEAD_INIT(type)  \
{                                 \
    _pyObject_EXTRA_INIT          \
    { _Py_IMMORTAL_REFCNT },      \
    (type)                        \
},

#define PyVarObject_HEAD_INIT(type, size) \
{                                         \
    PyObject_HEAD_INIT(type)              \
    (size)                                \
},

// python 中的 int 类型对象
PyTypeObject PyLong_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0),
    "int",
    // ...
};

将宏展开后, PyTypeObject 实例化的第一个参数是 PyVarObject 类型的, 而 PyVarObject 内部包含 PyObject ob_base;Py_ssize_t ob_size; 两个属性, 在 int 类型中, 后者是 0, 前者应该包含一个 union 类型的引用计数是 _Py_IMMORTAL_REFCNT, 以及一个 *PyTypeObject, 这里是 &PyType_Type.

PyTypeObject PyLong_Type = {
    {
        {
            { _Py_IMMORTAL_REFCNT },
            (&PyType_Type)
        },
        (0)
    },
    "int",
    // ...
};

那么 PyType_Type 是什么呢? 以下定义似乎在定义 PyType_Type 时使用了 PyType_Type, 这是什么原因呢

// Objects/typeobject.c
// PyType_Type 是一个全局变量(静态变量)
PyTypeObject PyType_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0),
    "type",
    // ...
}

解释: 这里用的是静态全局变量初始化的特性: 先分配了 MyType_Type 这个实例的地址, 所以在实例化时能使用其自身的地址进行实例化

#include <stdio.h>

// 定义一个结构体,包含一个指向自身类型的指针
typedef struct MyType {
    const char *name;
    struct MyType *type_ptr;
} MyType;

// 初始化一个全局变量,指向自身
MyType MyType_Type = {
    "MyType",        // name 字段
    &MyType_Type     // type_ptr 字段指向自己
};

int main() {
    // 打印 name 和 type_ptr 指向的结构体的 name
    printf("Type name: %s\n", MyType_Type.name);
    printf("Type name: %p\n", MyType_Type.type_ptr);
    printf("Type pointer name: %s\n", MyType_Type.type_ptr->name);
    printf("Type pointer name: %s\n", MyType_Type.type_ptr->type_ptr->name);
    printf("Type pointer name: %s\n", MyType_Type.type_ptr->type_ptr->type_ptr->name);

    return 0;
}

// 输出:
// Type name: MyType
// Type name: 0x55ac9fd46010
// Type pointer name: MyType
// Type pointer name: MyType
// Type pointer name: MyType

Last updated