如何不执行Py_CompileString生成的代码对象创建模块并绑定C++函数?
解决不执行Python代码先获取模块并嵌入C++函数的方案
要实现不执行Python代码先创建模块对象,再嵌入C++函数,最后执行模块代码的需求,你可以拆分步骤,绕过PyImport_ExecCodeModule(它会创建模块并立即执行代码),改用以下流程:
步骤1:创建空模块对象
先通过pybind11直接创建一个空模块,此时不会执行任何Python代码:
#include <pybind11/pybind11.h> namespace py = pybind11; // 创建空模块,命名为"my_module" py::module mod = py::module::create("my_module"); // 可选:将模块注册到sys.modules,方便后续Python代码import py::module sys = py::module::import("sys"); sys.attr("modules")["my_module"] = mod;
步骤2:嵌入C++函数到模块
直接用pybind11的def方法给空模块添加C++函数,此时模块已经存在,且未执行任何Python代码:
// 嵌入func1 mod.def("func1", []() { return "This is from C++ func1"; }); // 嵌入func2 mod.def("func2", [](int a, int b) { return a + b; });
步骤3:编译Python代码为Code对象
用Py_CompileString将Python代码编译为Code对象(这一步不会执行代码,只是编译):
const char* myCode = R"( print('Hello from Python code') print('Call func1:', func1()) print('Call func2(2,3):', func2(2,3)) )"; // 编译代码,Py_file_input表示按文件模式编译 PyObject* codeObj = Py_CompileString(myCode, "<embedded_code>", Py_file_input); if (!codeObj) { py::error_already_set(); throw std::runtime_error("Failed to compile Python code"); }
步骤4:在模块上下文中执行Code对象
由于不能用pybind11::exec,可以直接调用Python C API的PyEval_EvalCode,在模块的命名空间中执行编译好的代码——此时模块已经有了嵌入的C++函数,Python代码可以直接调用:
// 获取模块的全局命名空间__dict__ py::dict modDict = mod.attr("__dict__"); // 在模块上下文中执行代码 PyEval_EvalCode(reinterpret_cast<PyCodeObject*>(codeObj), modDict.ptr(), modDict.ptr()); // 检查执行错误 if (PyErr_Occurred()) { py::error_already_set(); throw std::runtime_error("Failed to execute Python code"); } // 释放Code对象的引用 Py_DECREF(codeObj);
关键说明
py::module::create(底层封装PyModule_New)只会创建空模块,不会执行任何代码,满足你“先获取模块对象”的需求。- 先嵌入C++函数再执行Python代码,确保Python代码能直接调用这些函数。
- 注册模块到
sys.modules后,后续Python代码可以通过import my_module直接使用该模块及嵌入的函数。
内容的提问来源于stack exchange,提问作者qssh
相关产品推荐
相关产品推荐

