如何用Python C Extension编写完整的高性能Python类?
没问题,我来给你展示怎么用纯Python C Extension实现你要的ClassName类,完全不依赖ctypes、Boost.Python或SWIG这类工具,纯C编写,性能拉满。
纯C实现Python扩展类完整示例
咱们分三个部分来:核心C代码、编译配置、测试步骤,每部分都给你讲清楚逻辑。
1. 核心C代码(mycextensionsmodule.c)
这部分是整个扩展的核心,包含了类的实例结构、初始化方法、talk方法,还有模块和类的注册逻辑:
#include <Python.h> // 定义类的实例结构体,用来存储实例的属性(对应Python中的self.hello) typedef struct { PyObject_HEAD PyObject* hello; // 存储hello属性,用PyObject*兼容所有Python对象 } ClassNameObject; // 对应Python类的__init__方法 static int ClassName_init(ClassNameObject* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = {"hello", NULL}; PyObject* hello = NULL; // 解析传入的hello参数,支持关键字传参 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &hello)) { return -1; } // 增加引用计数,避免属性被Python垃圾回收 self->hello = Py_NewRef(hello); return 0; } // 对应Python类的talk方法 static PyObject* ClassName_talk(ClassNameObject* self, PyObject* args) { PyObject* world = NULL; // 解析传入的world参数 if (!PyArg_ParseTuple(args, "O", &world)) { return NULL; } // 格式化字符串,和Python的"%s %s"逻辑一致 PyObject* result = PyUnicode_FromFormat("%U %U", self->hello, world); if (result == NULL) { return NULL; } // 打印结果,对应Python的print函数 PyObject_Print(result, stdout, 0); Py_NewLine(stdout); // 返回None,因为原Python方法没有返回值 Py_DECREF(result); Py_RETURN_NONE; } // 类的方法列表,把talk方法注册进去 static PyMethodDef ClassName_methods[] = { {"talk", (PyCFunction)ClassName_talk, METH_VARARGS, "Print hello and world"}, {NULL} // 方法列表结束标记 }; // 类的类型对象,定义类的元信息 static PyTypeObject ClassNameType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "mycextensionsmodule.ClassName", // 类的全名:模块名.类名 .tp_doc = "docstring for ClassName", // 类的文档字符串 .tp_basicsize = sizeof(ClassNameObject), // 实例结构体的大小 .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // 类的基础标志 .tp_init = (initproc)ClassName_init, // 绑定初始化方法 .tp_methods = ClassName_methods, // 绑定方法列表 .tp_dealloc = (destructor)PyObject_Del, // 析构方法,用默认的即可 }; // 模块的方法列表(这里模块没有额外方法,只有类) static PyMethodDef module_methods[] = { {NULL} }; // 模块定义结构体 static struct PyModuleDef mycextensionsmodule = { PyModuleDef_HEAD_INIT, .m_name = "mycextensionsmodule", // 模块名称 .m_doc = "A module with a pure C implemented ClassName", // 模块文档 .m_size = -1, .m_methods = module_methods, }; // 模块初始化函数,Python导入模块时会调用这个函数 PyMODINIT_FUNC PyInit_mycextensionsmodule(void) { PyObject* m; // 准备类的类型对象 if (PyType_Ready(&ClassNameType) < 0) { return NULL; } // 创建模块对象 m = PyModule_Create(&mycextensionsmodule); if (m == NULL) { return NULL; } // 将ClassName类添加到模块中 Py_INCREF(&ClassNameType); if (PyModule_AddObject(m, "ClassName", (PyObject*)&ClassNameType) < 0) { Py_DECREF(&ClassNameType); Py_DECREF(m); return NULL; } return m; }
2. 编译配置文件(setup.py)
用setuptools来编译扩展模块,这个是Python官方推荐的方式,不用手动写gcc命令:
from setuptools import setup, Extension # 定义扩展模块,指定源文件 module = Extension('mycextensionsmodule', sources=['mycextensionsmodule.c']) setup( name='mycextensionsmodule', version='1.0', description='Example of pure C Python class extension', ext_modules=[module] )
3. 测试步骤
按照下面的步骤就能运行起来:
- 把上面两个文件放在同一个文件夹里
- 打开终端,进入该文件夹,运行编译命令:
python setup.py build_ext --inplace - 然后创建一个Python脚本测试:
from mycextensionsmodule import ClassName classname = ClassName("Hello") classname.talk('world!') # 会输出:Hello world!
关键逻辑说明
- 实例结构体:
ClassNameObject对应每个Python实例,里面的hello字段存储实例属性,用PyObject*可以兼容所有Python对象类型(字符串、数字都可以) - 引用计数:用
Py_NewRef和Py_DECREF管理对象的引用,避免Python垃圾回收机制误释放属性 - 方法注册:通过
PyMethodDef把C函数绑定成Python类的方法,METH_VARARGS表示方法接受位置参数 - 类型对象:
PyTypeObject是Python C API中定义类的核心,它包含了类的所有元信息和行为
如果需要拓展功能,比如添加更多属性、方法,或者实现特殊方法(比如__str__),只需要在这个基础上修改:添加字段到实例结构体,新增C函数,然后更新方法列表或者类型对象的对应字段即可。
内容的提问来源于stack exchange,提问作者Evandro Coan
相关产品推荐
相关产品推荐

