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

C++嵌入Python调用hello_world.py中say_hello函数时pModule为nullptr的问题解决求助

解决C++嵌入Python时PyImport_Import返回nullptr的问题

我来帮你排查这个问题——PyImport_Import返回nullptr的核心原因几乎都是Python解释器找不到你的hello_world模块,结合你的目录结构,我们一步步解决:

第一步:先添加错误诊断代码,明确具体问题

你的C++代码目前没有错误检查逻辑,这很难定位具体问题。在调用PyImport_Import后立即加上错误打印,能直接看到Python抛出的异常信息:

pName = PyUnicode_FromString("hello_world");
pModule = PyImport_Import(pName);
if (pModule == nullptr) {
    PyErr_Print(); // 打印Python的错误信息,这会告诉你到底为什么找不到模块
    Py_DECREF(pName);
    Py_Finalize();
    return 1;
}

运行后你大概率会看到类似ModuleNotFoundError: No module named 'hello_world'的错误,这就坐实了路径问题。

第二步:把hello_world.py所在目录加入Python的sys.path

Python只会在sys.path列表里的目录查找模块,而你的程序运行时的工作目录大概率是项目根目录(不是src目录),所以需要手动把src目录添加进去。在Py_Initialize之后、导入模块之前添加这段代码:

Py_Initialize();
Py_SetProgramName((wchar_t*)argv[0]);

// 新增:添加src目录到sys.path
PyObject* sysPath = PySys_GetObject((char*)"path");
const char* srcDir = "./src"; // 相对于项目根目录的路径,若运行目录不同需调整
PyList_Append(sysPath, PyUnicode_FromString(srcDir));

如果你的可执行文件生成在构建子目录(比如build/bin),更稳妥的方式是通过argv[0]动态获取路径:

#include <filesystem>
namespace fs = std::filesystem;

// ... 在Py_Initialize之后
fs::path exePath = fs::absolute(argv[0]);
fs::path srcDir = exePath.parent_path() / "../src"; // 适配build/bin到src的相对路径
PyList_Append(sysPath, PyUnicode_FromString(srcDir.c_str()));

第三步:完善C++代码的内存管理和错误检查

你的代码还缺少对PyObject的引用计数管理,容易引发内存泄漏。修改后的完整代码如下:

#include <python3.10/Python.h>
#include <exception>
#include <filesystem>
#include <cstdio>

namespace fs = std::filesystem;

int main(int argc, char* argv[]) {
    if (!Py_Initialize()) {
        fprintf(stderr, "Failed to initialize Python interpreter\n");
        return 1;
    }
    Py_SetProgramName((wchar_t*)argv[0]);

    // 添加src目录到sys.path
    PyObject* sysPath = PySys_GetObject((char*)"path");
    if (!sysPath) {
        PyErr_Print();
        Py_Finalize();
        return 1;
    }
    fs::path exePath = fs::absolute(argv[0]);
    fs::path srcDir = exePath.parent_path() / "../src";
    PyObject* srcPathObj = PyUnicode_FromString(srcDir.c_str());
    if (!srcPathObj || PyList_Append(sysPath, srcPathObj) == -1) {
        PyErr_Print();
        Py_XDECREF(srcPathObj);
        Py_Finalize();
        return 1;
    }
    Py_DECREF(srcPathObj);

    PyObject *pModule, *pName, *pDict, *pFunc;
    pName = PyUnicode_FromString("hello_world");
    if (!pName) {
        PyErr_Print();
        Py_Finalize();
        return 1;
    }

    pModule = PyImport_Import(pName);
    if (!pModule) {
        PyErr_Print();
        Py_DECREF(pName);
        Py_Finalize();
        return 1;
    }
    Py_DECREF(pName);

    pDict = PyModule_GetDict(pModule);
    if (!pDict) {
        PyErr_Print();
        Py_DECREF(pModule);
        Py_Finalize();
        return 1;
    }

    pFunc = PyDict_GetItemString(pDict, "say_hello");
    if (!pFunc || !PyCallable_Check(pFunc)) {
        PyErr_Print();
        Py_DECREF(pModule);
        Py_Finalize();
        return 1;
    }

    PyObject* result = PyObject_CallObject(pFunc, NULL);
    if (!result) {
        PyErr_Print();
    }
    Py_XDECREF(result);

    Py_DECREF(pModule);
    Py_Finalize();
    return 0;
}

第四步:优化CMake配置细节

你的CMakeLists存在重复调用find_package(Python)的问题,根目录已经配置过的话,src目录无需重复调用。另外可以指定可执行文件输出路径,让路径拼接更稳定:
在根目录的CMakeLists.txt中添加:

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)

这样可执行文件会生成在build/bin目录下,和代码里的../src路径逻辑完全匹配。

最后,确保hello_world.py确实在src目录下,从项目根目录运行可执行文件即可正常调用Python函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 20:28:09