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

从C++导入Python模块遇ModuleNotFoundError及Py_SetPath用法问题

解决C++嵌入Python时的模块导入与路径配置问题

问题1:ModuleNotFoundError: No module named '.' 根源

你直接给PyImport_ImportModule传了../test/test.py这个文件路径,但这个函数的设计是接受模块名(比如test),不是带路径和后缀的文件名。Python会把../test/test.py解析成包含.的无效模块名,直接触发找不到模块的错误。

问题2:ModuleNotFoundError: No module named 'encodings' 根源

Py_SetPath会完全覆盖Python默认的sys.path,如果你只设置了自己的项目路径,Python就找不到自带的标准库(比如encodings),从而启动崩溃。正确做法是在原有sys.path基础上添加自己的路径,而非直接替换。


修正后的完整代码

添加了错误打印调试、正确的路径处理和sys.path配置:

#include <Python.h>
#include <filesystem>
#include <iostream>
#include <string>

namespace fs = std::filesystem;

// 打印Python详细错误栈,调试必备
void print_python_error() {
    PyErr_Print();
}

int python_exec(const fs::path& module_dir, const std::string& module_name, std::string_view function) {
    // 将模块所在目录添加到Python的搜索路径
    PyObject* sys_path = PySys_GetObject("path");
    PyObject* dir_path = PyUnicode_FromString(module_dir.string().c_str());
    if (!dir_path || PyList_Append(sys_path, dir_path) == -1) {
        print_python_error();
        Py_XDECREF(dir_path);
        return -1;
    }
    Py_DECREF(dir_path);

    // 导入目标模块
    PyObject* module = PyImport_ImportModule(module_name.c_str());
    if (!module) {
        print_python_error();
        return -1;
    }

    // 获取目标函数
    PyObject* symbol = PyObject_GetAttrString(module, function.data());
    if (!symbol) {
        print_python_error();
        Py_DECREF(module);
        return -1;
    }

    // 调用函数并返回结果
    int result = -1;
    if (PyCallable_Check(symbol)) {
        PyObject* value = PyObject_CallObject(symbol, nullptr);
        if (value) {
            result = PyLong_AsLong(value);
            Py_DECREF(value);
        } else {
            print_python_error();
        }
    } else {
        std::cerr << "指定符号不是可调用函数" << std::endl;
    }

    // 清理Python对象,避免内存泄漏
    Py_DECREF(symbol);
    Py_DECREF(module);
    return result;
}

int main(int argc, char** argv) {
    if (argc < 2) {
        std::cerr << "用法: " << argv[0] << " <模块文件路径>" << std::endl;
        return 1;
    }

    const fs::path module_path = argv[1];
    const fs::path module_dir = module_path.parent_path(); // 提取模块所在目录(比如../test)
    const std::string module_name = module_path.stem().string(); // 提取模块名(比如test)

    // 初始化Python环境
    Py_Initialize();

    // 执行Python函数并输出结果
    std::cout << python_exec(module_dir, module_name, "my_func") << std::endl;

    // 清理Python环境
    Py_Finalize();
    return 0;
}

关键注意事项

  • 模块导入规则:PyImport_ImportModule只接受模块名,不能传文件路径。需先把模块所在目录加入sys.path,再导入模块名。
  • sys.path配置:不要用Py_SetPath直接覆盖默认路径,而是通过PySys_GetObject("path")获取原有路径列表,再添加自己的目录,避免破坏Python标准库的查找路径。
  • 错误调试:务必调用PyErr_Print()打印Python的错误栈,比单纯返回-1更容易定位问题。
  • 跨平台路径处理:用C++17的filesystem库处理路径,自动适配Windows和Linux的路径分隔符。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 11:05:38