Python C API
Python C API允许用C语言扩展Python或嵌入Python解释器,适用于性能关键场景和系统集成。
基础概念
所有Python对象在C层面都是PyObject*指针,包含引用计数和类型指针:
C
// PyObject 结构(简化)
typedef struct _object {
Py_ssize_t ob_refcnt; // 引用计数
PyTypeObject *ob_type; // 类型对象
} PyObject;
引用计数管理
C
#include <Python.h>
void refcount_demo(PyObject *obj) {
// 增加引用计数
Py_INCREF(obj);
// 减少引用计数
Py_DECREF(obj);
// 偷取引用(不增加计数,调用者负责释放)
Py_DECREF(obj); // 如果是偷取的引用
// 借用引用(不拥有,不负责释放)
// 如 PyList_GetItem 返回借用引用
PyObject *item = PyList_GetItem(list, 0); // 借用
Py_INCREF(item); // 需要时增加计数
}
注意:引用计数错误是C扩展最常见的问题,务必成对使用INCREF/DECREF。
创建C扩展模块
C
// mymodule.c
#define PY_SSIZE_T_CLEAN
#include <Python.h>
// 示例函数:计算两数之和
static PyObject* my_add(PyObject *self, PyObject *args) {
double a, b;
if (!PyArg_ParseTuple(args, "dd", &a, &b)) {
return NULL; // 解析失败,返回NULL触发异常
}
return PyFloat_FromDouble(a + b);
}
// 方法表
static PyMethodDef MyMethods[] = {
{"add", my_add, METH_VARARGS, "Add two numbers"},
{NULL, NULL, 0, NULL} // 哨兵
};
// 模块定义
static struct PyModuleDef mymodule = {
PyModuleDef_HEAD_INIT,
"mymodule", // 模块名
"Example module", // 文档
-1, // 每解释器状态大小,-1表示全局
MyMethods
};
// 初始化函数
PyMODINIT_FUNC PyInit_mymodule(void) {
return PyModule_Create(&mymodule);
}
编译安装(setup.py):
Python
from setuptools import Extension, setup
module = Extension(
'mymodule',
sources=['mymodule.c']
)
setup(
name='MyModule',
version='1.0',
ext_modules=[module]
)
Bash
python setup.py build_ext --inplace
参数解析
C
// 常用格式字符
// i - int
// l - long
// d - double
// s - char* (UTF-8)
// O - PyObject*
// O! - 特定类型的PyObject*
static PyObject* parse_demo(PyObject *self, PyObject *args) {
int num;
const char *str;
PyObject *list;
// "isO!" 表示:int, string, 必须是list的对象
if (!PyArg_ParseTuple(args, "isO!", &num, &str, &PyList_Type, &list)) {
return NULL;
}
// 解析关键字参数
PyObject *kwlist = PyList_New(0);
// ...
return Py_None;
}
// 关键字参数版本
static PyObject* kw_demo(PyObject *self, PyObject *args, PyObject *kwargs) {
int x = 0, y = 0;
static char *kwlist[] = {"x", "y", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &x, &y)) {
return NULL;
}
return PyLong_FromLong(x + y);
}
嵌入Python解释器
C
#include <Python.h>
int main(int argc, char *argv[]) {
// 初始化解释器
Py_Initialize();
// 执行Python代码
PyRun_SimpleString("print('Hello from embedded Python!')");
// 导入模块并调用函数
PyObject *math = PyImport_ImportModule("math");
PyObject *sqrt = PyObject_GetAttrString(math, "sqrt");
PyObject *result = PyObject_CallFunction(sqrt, "d", 2.0);
printf("sqrt(2) = %f\n", PyFloat_AsDouble(result));
// 清理
Py_DECREF(result);
Py_DECREF(sqrt);
Py_DECREF(math);
// 关闭解释器
Py_Finalize();
return 0;
}
类型定义
C
// 定义自定义类型
typedef struct {
PyObject_HEAD
int value;
} MyObject;
static void MyObject_dealloc(MyObject *self) {
Py_TYPE(self)->tp_free((PyObject *)self);
}
static PyObject* MyObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
MyObject *self;
self = (MyObject *)type->tp_alloc(type, 0);
if (self != NULL) {
self->value = 0;
}
return (PyObject *)self;
}
static int MyObject_init(MyObject *self, PyObject *args, PyObject *kwds) {
int value = 0;
static char *kwlist[] = {"value", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &value))
return -1;
self->value = value;
return 0;
}
static PyTypeObject MyObjectType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "mymodule.MyObject",
.tp_doc = "Custom object",
.tp_basicsize = sizeof(MyObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_new = MyObject_new,
.tp_init = (initproc)MyObject_init,
.tp_dealloc = (destructor)MyObject_dealloc,
};
要点总结
- **
PyObject***是所有Python对象的C表示 - 引用计数必须严格配对:
Py_INCREF/Py_DECREF - **
PyArg_ParseTuple**解析位置参数,PyArg_ParseTupleAndKeywords解析关键字参数 - 嵌入解释器使用
Py_Initialize/Py_Finalize - 类型定义需要实现
new、init、dealloc等槽位
📝 发现内容有误?点击此处直接编辑