从C++导入python模块时出错:ModuleNotFoundError:没有名为“.”的模块

icnyk63a  于 2023-07-01  发布在  Python
关注(0)|答案(1)|浏览(343)

我试图导入一个python模块并在C++中执行一个函数。我有以下代码片段:

int python_exec(const fs::path& module_path, std::string_view function) {
    const auto tmp = module_path.string();

    PyObject* module = PyImport_ImportModule(tmp.data());

    if (!module) {
        return -1;
    }

    PyObject* symbol = PyObject_GetAttrString(module, function.data());

    if (!symbol) {
        return - 1;
    }

    if (PyCallable_Check(symbol)) {
        PyObject* value = PyObject_CallObject(symbol, nullptr);
        return PyLong_AsLong(value);
    }

    return -1;
}

int main(int argc, char** argv)
{
    const auto current = fs::current_path();
    const auto module  = argv[1];

    std::cout << current << '\n';        // "C:\\full\\path\\to\\project\\cmake-build-debug"
    std::cout << module  << '\n';        // "../test/test.py"

    Py_Initialize();
    Py_SetPath(current.c_str());

    std::cout << python_exec(module, "my_func") << '\n';

    Py_Finalize();

    return 0;
}

以及以下项目结构:

project
|_cmake-build-debug
|    |_app.exe
|_test
     |_test.py

我的可执行文件在build目录中运行,我将"../test/test.py"作为程序参数传递
Python抛出ModuleNotFoundError: No module named '.'错误。
我还尝试在Py_Initialize之前调用Py_SetPath,如这里所建议的https://stackoverflow.com/a/63452021/22124714,但这导致了其他错误,我无法完全解释:

Python path configuration:
  PYTHONHOME = (not set)
  PYTHONPATH = (not set)
  program name = 'python'
  isolated = 0
  environment = 1
  user site = 1
  import site = 1
  sys._base_executable = 'C:\\full\\path\\to\\project\\cmake-build-debug\\pytest.exe'
  sys.base_prefix = ''
  sys.base_exec_prefix = ''
  sys.platlibdir = 'lib'
  sys.executable = 'C:\\full\\path\\to\\project\\cmake-build-debug\\pytest.exe'
  sys.prefix = ''
  sys.exec_prefix = ''
  sys.path = [
    'C:\\full\\path\\to\\project\\cmake-build-debug',
  ]
Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named 'encodings'

这两条线看起来很可疑。

PYTHONHOME = (not set)
PYTHONPATH = (not set)

我想我没有正确理解Py_SetPath函数,如何解决这个问题?

twh00eeo

twh00eeo1#

这个问题是关于Python用来查找模块的路径,也就是sys.path
设置路径的方法有多种:

  1. PySys_SetPath
Py_Initialize();
PySys_SetPath(L"../test")
  1. PyList_Append
void Py_AppendPath(std::string_view module_dir)
{
    PyObject* msys = PyImport_ImportModule("sys");
    PyObject* path = PyObject_GetAttrString(msys, "path");

    PyList_Append(path, PyUnicode_FromString(module_dir.data()));
}

Py_Initialize();
Py_AppendPath("../test");
  1. PyRun_SimpleString()
const fs::path moddir = fs::absolute(argv[1]).remove_filename();
const std::string ex = std::format(R"(sys.path.append(r"{}\"))", moddir.string());
PyRun_SimpleString("import sys");
PyRun_SimpleString(ex.data());

注意事项:

  • 避免将您的模块命名为“test”,因为已经存在一个
  • PyImport_ImportModule只取模块名,省略文件扩展名。
  • 代码没有错误检查和引用计数来使其更清晰。一定要处理好这些!

相关问题