2. 定义扩展类型:教程

Python 允许 C 扩展模块作者定义可以从 Python 代码操纵的新类型,非常像内置 str and list 类型。所有扩展类型代码遵循模式,但开始之前需要了解一些细节。此文档是话题的温柔介绍。

2.1. 基础

The CPython 运行时将所有 Python 对象视为变量类型 PyObject * ,充当所有 Python 对象的 "基类型"。 PyObject 结构本身仅包含对象的 引用计数 和指向对象 "类型对象" 的指针。这是行动所在;类型对象确定解释器调用哪些 C 函数,例如,查找对象属性、调用方法、或乘以另一对象。这些 C 函数称为 "类型方法"。

所以,若想要定义新扩展类型,需要创建新类型对象。

这种事情只能通过范例解释,所以这里最小但完整的模块,定义新类型名称 Custom 在 C 扩展名模块 custom :

注意

这里展示以传统方式定义的 static 扩展类型。它应该足以满足大多数用法。 C API 还允许定义堆分配扩展类型使用 PyType_FromSpec() 函数,此教程未涵盖。

#define PY_SSIZE_T_CLEAN
#include <Python.h>
typedef struct {
    PyObject_HEAD
    /* Type-specific fields go here. */
} CustomObject;
static PyTypeObject CustomType = {
    .ob_base = PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "custom.Custom",
    .tp_doc = PyDoc_STR("Custom objects"),
    .tp_basicsize = sizeof(CustomObject),
    .tp_itemsize = 0,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_new = PyType_GenericNew,
};
static PyModuleDef custommodule = {
    .m_base = PyModuleDef_HEAD_INIT,
    .m_name = "custom",
    .m_doc = "Example module that creates an extension type.",
    .m_size = -1,
};
PyMODINIT_FUNC
PyInit_custom(void)
{
    PyObject *m;
    if (PyType_Ready(&CustomType) < 0)
        return NULL;
    m = PyModule_Create(&custommodule);
    if (m == NULL)
        return NULL;
    if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
        Py_DECREF(m);
        return NULL;
    }
    return m;
}