linux 为什么PyImport_Import无法从当前目录加载模块?

gijlo24d  于 2022-12-22  发布在  Linux
关注(0)|答案(4)|浏览(216)

我正在尝试运行嵌入示例,但无法从当前工作目录加载模块,除非我显式地将其添加到sys.path,然后它才能工作:

PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append(\".\")");

Python不应该在当前目录中查找模块吗?

Edit1:尝试仅使用以下命令导入模块:

Py_Initialize();
PyRun_SimpleString("import multiply");

但它仍然失败,并出现以下错误:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named multiply

编辑2:来自sys.path文档:

如果脚本目录不可用(例如,如果解释器是交互式调用的,或者脚本是从标准输入读取的),path[0]是空字符串,它指示Python首先搜索当前目录中的模块
不确定 * 不可用 * 的含义,但如果我打印sys.path[0],则它不为空:

/usr/lib/pymodules/python2.7
kse8i1jr

kse8i1jr1#

您需要调用PySys_SetArgv(int argc, char **argv, int updatepath)才能使相对导入工作。如果updatepath0,这将把正在执行的脚本的路径添加到sys.path(更多信息请参阅文档)。
下面的代码应该可以实现这个目的

#include <Python.h>

int
main(int argc, char *argv[])
{
  Py_SetProgramName(argv[0]);  /* optional but recommended */
  Py_Initialize();
  PySys_SetArgv(argc, argv); // must call this to get sys.argv and relative imports
  PyRun_SimpleString("import os, sys\n"
                     "print sys.argv, \"\\n\".join(sys.path)\n"
                     "print os.getcwd()\n"
                     "import thing\n" // import a relative module
                     "thing.printer()\n");
  Py_Finalize();
  return 0;
}
p8h8hvxi

p8h8hvxi2#

我在python 3.5中所要做的就是PySys_SetPath,以便能够从cwd位置导入:

QString qs = QDir::currentPath();
std::wstring ws = qs.toStdWString();
PySys_SetPath(ws.data());

其中的Q是Qt。

csga3l58

csga3l583#

要从当前目录加载模块,有许多选项。
1.你需要通过一个初始化结构体来配置Python(包括路径配置),请参见Python初始化配置。

Py_Initialize():
//...
PyConfig config;
PyConfig_InitPythonConfig(&config);
config.module_search_paths_set = 1;
PyWideStringList_Append(&config.module_search_paths, L"."); // append local dir to path
Py_InitializeFromConfig(&config);
//...
pModule = PyImport_Import(pName); // import module

1.一个单行选项是在Py_Initialize()之后运行PySys_SetArgv(0, NULL);,将当前目录前置到Python的Path中。虽然这个选项从Python 3.11开始就不被使用了,但是它在很多情况下都是简单有效的选项。当满足以下条件时,这个选项利用了PySys_SetArgvEx(int argc, char **argv, int updatepath)的行为:

  • 非零updatepath
  • argc = 0argv指向现有文件名。

参见docs。从Python 2.7开始有效。为了添加一个特定的目录,argv[0]应该包含该目录中Python脚本的路径(例如"NULL")。PySys_SetArgv为你正确地设置updatepath的值。虽然,如前所述,这个选项当前被弃用

示例项目

加载当前目录下Python脚本中定义的模块,并调用该模块中的函数,所有这些都使用C应用程序的输入参数指定。为简单起见,删除了检查。本示例与文档页中提供的将Python嵌入C/C ++应用程序的示例密切相关。
./hello.py

def sayHello1():
  print("Hello from sayHello1!")
  return 1

def sayHello2():
  print("Hello from sayHello2!")
  return 2

./main.c

  • (为简单起见,删除了复选框)*
#define PY_SSIZE_T_CLEAN
#include <Python.h>

int main(int argc, char *argv[])
{
  PyObject *pName = NULL;
  PyObject *pModule = NULL;
  PyObject *pFunc = NULL;
  PyObject *pValue = NULL;

  Py_Initialize();
// PySys_SetArgv(0, NULL); // Option 2 [deprecated]

// Option 1 - Python Initialization api
  PyConfig config;
  PyConfig_InitPythonConfig(&config);
  config.module_search_paths_set = 1;
  PyWideStringList_Append(&config.module_search_paths, L".");
  Py_InitializeFromConfig(&config);
// ...

  pName = PyUnicode_FromString(argv[1]);
  pModule = PyImport_Import(pName);
  Py_XDECREF(pName);

  pFunc = PyObject_GetAttrString(pModule, argv[2]);
  pValue = PyObject_CallNoArgs(pFunc); // actual call to the fcn

  Py_XDECREF(pValue);
  Py_XDECREF(pFunc);
  Py_XDECREF(pModule);
  
  Py_Finalize();
  return 0;
}

编译(cmake):
一个三个三个一个
执行:

./call hello sayHello1
Hello from sayHello1!

./call hello sayHello2
Hello from sayHello2!
ar5n3qh5

ar5n3qh54#

我遇到了完全相同的问题,我只是通过添加Py_Initialize();Py_Finalize();来解决它
希望能帮到你

相关问题