You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python C API创建持有C函数指针的PyObject以调用Python函数

用Python C API将C函数包装为PyObject传给Python函数调用

核心思路

要让Python函数foo能调用你的C函数bar,得先把bar包装成符合Python调用规范的可调用对象,再打包成参数元组传给foo。

具体实现步骤

  1. 编写C包装函数
    这个函数要遵循Python C API的签名规则,内部调用你的bar函数,最后返回Python的None:

    static PyObject* wrap_bar(PyObject* self, PyObject* args) {
        bar();
        Py_RETURN_NONE;
    }
    
  2. 定义方法描述结构体
    告诉Python包装函数的参数类型等关键信息:

    static PyMethodDef bar_method_def = {
        "bar",          // Python中显示的函数名
        wrap_bar,       // 对应的C包装函数指针
        METH_NOARGS,    // 标记该函数无参数
        NULL            // 文档字符串,可设为NULL
    };
    
  3. 创建可调用的PyObject
    基于上面的方法描述生成Python可调用对象:

    PyObject* bar_obj = PyCFunction_New(&bar_method_def, NULL);
    if (!bar_obj) {
        // 处理创建失败的情况,比如返回NULL或抛出异常
        return NULL;
    }
    
  4. 构建参数元组
    因为foo需要一个参数,创建长度为1的元组并将bar_obj放入:

    PyObject* args = PyTuple_New(1);
    if (!args) {
        Py_DECREF(bar_obj); // 释放已分配的对象,避免内存泄漏
        return NULL;
    }
    // PyTuple_SetItem会接管bar_obj的引用,无需手动调用Py_DECREF
    if (PyTuple_SetItem(args, 0, bar_obj) != 0) {
        Py_DECREF(args);
        Py_DECREF(bar_obj);
        return NULL;
    }
    
  5. 调用Python函数foo
    将参数元组传入PyObject_Call完成调用:

    PyObject* function = PyObject_GetAttrString(module, "foo");
    if (!function) {
        Py_DECREF(args);
        return NULL;
    }
    PyObject* result = PyObject_Call(function, args, NULL);
    // 释放不再使用的对象
    Py_DECREF(function);
    Py_DECREF(args);
    if (!result) {
        // 处理调用失败的情况
        return NULL;
    }
    // 使用完result后记得释放
    Py_DECREF(result);
    

注意事项

  • 所有创建的PyObject,在不再使用时必须用Py_DECREF释放,防止内存泄漏。
  • 每一步都要检查返回值是否为NULL,及时处理异常场景。

内容的提问来源于stack exchange,提问作者Marko Devcic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 13:27:10