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

如何在同一进程中实现Python调用C++后再由C++调用Python?

同一进程内Python→C++→Python嵌套调用的实现方案

当然可以实现这种无额外线程/进程的调用流程!核心是利用Python C API复用当前运行的Python解释器实例——你的上层Python代码本身就在一个活跃的解释器进程里,C++扩展直接对接这个实例即可完成双向调用,完全不需要新建进程或线程。

核心原理

上层Python调用C扩展时,当前的Python解释器状态是激活的。C代码可以通过Python C API直接:

  • 导入指定的Python模块/函数
  • 传递参数并调用Python函数
  • 获取Python函数的返回值并转换为C++类型
  • 继续执行C++逻辑后,再把结果返回给上层Python

整个流程全程在同一个线程、同一个进程内完成,没有跨进程/线程的通信开销。

完整示例代码

下面是一个可直接运行的示例,涵盖从C++扩展编写到上层Python调用的全流程:

1. 准备被C++调用的Python逻辑(py_logic.py)

def process_in_py(input_data):
    """这是C++要调用的Python计算函数"""
    print(f"[Python子函数] 收到C++传递的数据: {input_data}")
    # 模拟你的Python计算逻辑
    processed_result = input_data * 2 + 1
    return processed_result

2. 编写C++扩展代码(cpp_extension.cpp)

#include <Python.h>

// 上层Python直接调用的C++入口函数
static PyObject* cpp_main(PyObject* self, PyObject* args) {
    int input_val;
    // 解析上层Python传递的参数
    if (!PyArg_ParseTuple(args, "i", &input_val)) {
        return NULL; // 参数解析失败会自动设置Python异常
    }

    // --- 第一步:执行C++自身的计算逻辑 ---
    int cpp_processed = input_val + 10;
    printf("[C++] 完成初始计算,结果: %d\n", cpp_processed);

    // --- 第二步:调用Python子函数 ---
    // 1. 导入目标Python模块(确保模块在Python的sys.path中)
    PyObject* py_module = PyImport_ImportModule("py_logic");
    if (!py_module) {
        PyErr_Print(); // 打印Python侧的错误信息
        return NULL;
    }

    // 2. 获取模块中的目标函数
    PyObject* py_func = PyObject_GetAttrString(py_module, "process_in_py");
    if (!py_func || !PyCallable_Check(py_func)) {
        PyErr_Print();
        Py_XDECREF(py_module); // 清理已分配的Python对象,避免内存泄漏
        return NULL;
    }

    // 3. 准备传递给Python函数的参数(这里是一个整数)
    PyObject* py_args = PyTuple_New(1);
    PyTuple_SetItem(py_args, 0, PyLong_FromLong(cpp_processed));

    // 4. 调用Python函数并获取返回值
    PyObject* py_result = PyObject_CallObject(py_func, py_args);
    // 临时对象用完必须释放,维护Python引用计数
    Py_DECREF(py_args);
    Py_DECREF(py_func);
    Py_DECREF(py_module);

    if (!py_result) {
        PyErr_Print();
        return NULL;
    }

    // 5. 将Python返回值转换为C++类型
    int py_processed_val = PyLong_AsLong(py_result);
    Py_DECREF(py_result);

    // --- 第三步:C++继续执行后续逻辑 ---
    int final_result = py_processed_val + 5;
    printf("[C++] 完成最终计算,结果: %d\n", final_result);

    // 返回最终结果给上层Python
    return PyLong_FromLong(final_result);
}

// 注册C++暴露给Python的方法
static PyMethodDef CppExtensionMethods[] = {
    {"cpp_main", cpp_main, METH_VARARGS, "C++入口函数,调用Python子函数处理数据"},
    {NULL, NULL, 0, NULL} // 方法列表结束标记
};

// 模块定义
static struct PyModuleDef cpp_extension_module = {
    PyModuleDef_HEAD_INIT,
    "cpp_extension", // 模块名称(上层Python导入时用这个名字)
    "Python调用C++再回调Python的扩展模块", // 模块文档
    -1, // 保持全局状态(无需子解释器)
    CppExtensionMethods
};

// 模块初始化函数(必须命名为PyInit_<模块名>)
PyMODINIT_FUNC PyInit_cpp_extension(void) {
    return PyModule_Create(&cpp_extension_module);
}

3. 编译C++扩展

  • Linux/macOS:用g++编译成.so文件,替换python3.x为你实际的Python版本(比如3.8、3.10)
    g++ -shared -fPIC -I/usr/include/python3.x -o cpp_extension.so cpp_extension.cpp
    
  • Windows:用MSVC编译成.pyd文件(Python的动态扩展格式),需要配置Python的include和lib路径,示例命令:
    cl /LD /I "C:\Python310\include" cpp_extension.cpp /link /LIBPATH:"C:\Python310\libs" python310.lib
    

4. 上层Python调用测试(main.py)

import sys
sys.path.append(".") # 确保扩展模块和py_logic在当前路径

import cpp_extension

# 调用C++扩展函数
input_value = 3
final_output = cpp_extension.cpp_main(input_value)
print(f"[上层Python] 收到最终结果: {final_output}")

关键注意事项

  • 引用计数管理:所有通过Python C API创建/获取的Python对象,用完必须用Py_DECREF释放,避免内存泄漏。Py_XDECREF可以安全处理NULL指针。
  • 模块路径:确保被C++调用的py_logic.py在Python的sys.path中,否则PyImport_ImportModule会失败。
  • 错误处理:每次调用Python API后检查返回值,用PyErr_Print()打印Python侧的异常信息,便于调试。
  • 复杂数据类型:如果需要传递列表、字典等复杂结构,可使用PyList_New、PyDict_SetItem等Python C API函数处理。
  • GIL管理:如果是多线程场景需要调用Python代码,要先用PyGILState_Ensure()获取GIL,用完用PyGILState_Release()释放;但单线程下无需额外处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:09:52