从不同目录调用多个 python 函数
Call multiple python functions from different directories
我有一些代码将转到目录(用于演示目的的文件夹 1),然后调用文件 python_function.py
中名为 function
的函数。代码如下所示:
#include <Python.h>
#include <string>
#include <iostream>
int main()
{
PyObject *pName, *pModule, *pDict, *pFunc;
setenv("PYTHONDONTWRITEBYTECODE", " ", 1);
// Initialize the Python Interpreter
Py_Initialize();
//CALL FUNCTION FROM FOLDER 1:
std::wstring pathWide = L"./Folder 1";
PySys_SetPath(pathWide.c_str());
// Build the name object
pName = PyUnicode_FromString((char*)"python_function");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, (char*)"function");
if (pFunc != NULL)
{
if (PyCallable_Check(pFunc))
{
PyObject *pResult;
pResult = PyObject_CallFunction(pFunc, "");
Py_DECREF(pResult);
}
else {PyErr_Print();}
}
else {std::cout << "pFunc is NULL!" << std::endl;}
// Clean up
Py_DECREF(pFunc);
Py_DECREF(pDict);
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
return 0;
}
此代码在我的系统上编译和运行完美,但当我想调用第二个目录(称为文件夹 2)中的另一个函数时,我收到错误:Segmentation Fault (core dumped)
。这是代码:
#include <Python.h>
#include <string>
#include <iostream>
int main()
{
PyObject *pName, *pModule, *pDict, *pFunc;
setenv("PYTHONDONTWRITEBYTECODE", " ", 1);
// Initialize the Python Interpreter
Py_Initialize();
//CALL FUNCTION FROM FOLDER 1:
std::wstring pathWide = L"./Folder 1";
PySys_SetPath(pathWide.c_str());
// Build the name object
pName = PyUnicode_FromString((char*)"python_function");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, (char*)"function");
if (pFunc != NULL)
{
if (PyCallable_Check(pFunc))
{
PyObject *pResult;
pResult = PyObject_CallFunction(pFunc, "");
Py_DECREF(pResult);
}
else {PyErr_Print();}
}
else {std::cout << "pFunc is NULL!" << std::endl;}
//CALL FUNCTION FROM FOLDER 2:
pathWide = L"./Folder 2";
PySys_SetPath(pathWide.c_str());
// Build the name object
pName = PyUnicode_FromString((char*)"python_function");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, (char*)"function");
if (pFunc != NULL)
{
if (PyCallable_Check(pFunc))
{
PyObject *pResult;
pResult = PyObject_CallFunction(pFunc, "");
Py_DECREF(pResult);
}
else {PyErr_Print();}
}
else {std::cout << "pFunc is NULL!" << std::endl;}
// Clean up
Py_DECREF(pFunc);
Py_DECREF(pDict);
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
return 0;
}
错误发生在我调用第一个函数之后,所以它似乎没有改变目录或其他东西。我正在使用 Ubuntu 并且我有 python 3.4
我试过其他改变目录的方法,不只是PySys_SetPath
,还有setenv("PYTHONPATH", path, 1);
注意:我现在不担心错误检测,我宁愿拥有在理想情况下工作的代码,然后担心不完美的情况。
编辑:
调试输出:
#0 0x7ffff79b16cb PyModule_GetDict() (/usr/lib/x86_64-linux-gnu/libpython3.4m.so.1.0:??)
#1 0x4010e6 main() (/home/ben/Documents/Programming/Projects/PYTHON TEST/main.cpp:23)
奇怪的是调试说错误发生在第 23 行,但是如果你 运行 第一个代码段
第 23 行不会导致错误
对彼得·布里坦的回答的回应:
如果我将第二个 PyImport_Import()
替换为 PyImport_ReloadModule()
,我会在控制台上打印一条错误消息,如下所示:
ImportError: No module named 'imp'
Error in sys.excepthook:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 53, in apport_excepthook
if not enabled():
File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 24, in enabled
import re
ImportError: No module named 're'
Original exception was:
ImportError: No module named 'imp'
编辑:更新了对发现的错误的进一步回答。
您未能在调试输出中导入您的模块。当 运行 在调试器之外时,您会遇到不能仅使用相同导入调用导入的问题。完整的问题链是这样的。
调试时:
- 您的调试器没有设置正确的当前工作目录。
- 相对路径无效,但被
PySys_SetPath()
接受。
- 因此您从
PyImport_Import()
得到 NULL,表明导入失败(如调试器下 here 所记录。
- 由于您没有检查错误,您将 NULL 传递给下一个函数,该函数尝试取消引用指针并因分段错误而失败。
我遇到了 Python2.7 的问题(使用 char* 而不是 wchar* - 如下面的评论所述)。把它放在一边,当 运行 正常时:
- 相对路径有效并被
PySys_SetPath()
接受。
- 因此您第一次成功加载了模块。
- 然后您 运行 完成其余代码,但这次它在第二次导入时出现分段错误。这是因为您不能以这种方式重新加载模块。您需要改用
PyImport_ReloadModule()
。
- 即使进行了该修复,您仍会发现无法加载标准库。那是因为您已经删除了系统路径的其余部分。您需要遵循建议 here.
所以,修复是:
- 使用
std::string
而不是 std::wstring
(对于 Python 2.x)。
- 重新加载模块时使用
PyImport_ReloadModule()
。
- 确保在设置路径时包含完整的 sys.path。
- 检查你的错误 - 对于大多数问题,我使用
PyErr_Print()
得到了明确的模块导入错误。
我有一些代码将转到目录(用于演示目的的文件夹 1),然后调用文件 python_function.py
中名为 function
的函数。代码如下所示:
#include <Python.h>
#include <string>
#include <iostream>
int main()
{
PyObject *pName, *pModule, *pDict, *pFunc;
setenv("PYTHONDONTWRITEBYTECODE", " ", 1);
// Initialize the Python Interpreter
Py_Initialize();
//CALL FUNCTION FROM FOLDER 1:
std::wstring pathWide = L"./Folder 1";
PySys_SetPath(pathWide.c_str());
// Build the name object
pName = PyUnicode_FromString((char*)"python_function");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, (char*)"function");
if (pFunc != NULL)
{
if (PyCallable_Check(pFunc))
{
PyObject *pResult;
pResult = PyObject_CallFunction(pFunc, "");
Py_DECREF(pResult);
}
else {PyErr_Print();}
}
else {std::cout << "pFunc is NULL!" << std::endl;}
// Clean up
Py_DECREF(pFunc);
Py_DECREF(pDict);
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
return 0;
}
此代码在我的系统上编译和运行完美,但当我想调用第二个目录(称为文件夹 2)中的另一个函数时,我收到错误:Segmentation Fault (core dumped)
。这是代码:
#include <Python.h>
#include <string>
#include <iostream>
int main()
{
PyObject *pName, *pModule, *pDict, *pFunc;
setenv("PYTHONDONTWRITEBYTECODE", " ", 1);
// Initialize the Python Interpreter
Py_Initialize();
//CALL FUNCTION FROM FOLDER 1:
std::wstring pathWide = L"./Folder 1";
PySys_SetPath(pathWide.c_str());
// Build the name object
pName = PyUnicode_FromString((char*)"python_function");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, (char*)"function");
if (pFunc != NULL)
{
if (PyCallable_Check(pFunc))
{
PyObject *pResult;
pResult = PyObject_CallFunction(pFunc, "");
Py_DECREF(pResult);
}
else {PyErr_Print();}
}
else {std::cout << "pFunc is NULL!" << std::endl;}
//CALL FUNCTION FROM FOLDER 2:
pathWide = L"./Folder 2";
PySys_SetPath(pathWide.c_str());
// Build the name object
pName = PyUnicode_FromString((char*)"python_function");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, (char*)"function");
if (pFunc != NULL)
{
if (PyCallable_Check(pFunc))
{
PyObject *pResult;
pResult = PyObject_CallFunction(pFunc, "");
Py_DECREF(pResult);
}
else {PyErr_Print();}
}
else {std::cout << "pFunc is NULL!" << std::endl;}
// Clean up
Py_DECREF(pFunc);
Py_DECREF(pDict);
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
return 0;
}
错误发生在我调用第一个函数之后,所以它似乎没有改变目录或其他东西。我正在使用 Ubuntu 并且我有 python 3.4
我试过其他改变目录的方法,不只是PySys_SetPath
,还有setenv("PYTHONPATH", path, 1);
注意:我现在不担心错误检测,我宁愿拥有在理想情况下工作的代码,然后担心不完美的情况。
编辑:
调试输出:
#0 0x7ffff79b16cb PyModule_GetDict() (/usr/lib/x86_64-linux-gnu/libpython3.4m.so.1.0:??)
#1 0x4010e6 main() (/home/ben/Documents/Programming/Projects/PYTHON TEST/main.cpp:23)
奇怪的是调试说错误发生在第 23 行,但是如果你 运行 第一个代码段
第 23 行不会导致错误对彼得·布里坦的回答的回应:
如果我将第二个 PyImport_Import()
替换为 PyImport_ReloadModule()
,我会在控制台上打印一条错误消息,如下所示:
ImportError: No module named 'imp'
Error in sys.excepthook:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 53, in apport_excepthook
if not enabled():
File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 24, in enabled
import re
ImportError: No module named 're'
Original exception was:
ImportError: No module named 'imp'
编辑:更新了对发现的错误的进一步回答。
您未能在调试输出中导入您的模块。当 运行 在调试器之外时,您会遇到不能仅使用相同导入调用导入的问题。完整的问题链是这样的。
调试时:
- 您的调试器没有设置正确的当前工作目录。
- 相对路径无效,但被
PySys_SetPath()
接受。 - 因此您从
PyImport_Import()
得到 NULL,表明导入失败(如调试器下 here 所记录。 - 由于您没有检查错误,您将 NULL 传递给下一个函数,该函数尝试取消引用指针并因分段错误而失败。
我遇到了 Python2.7 的问题(使用 char* 而不是 wchar* - 如下面的评论所述)。把它放在一边,当 运行 正常时:
- 相对路径有效并被
PySys_SetPath()
接受。 - 因此您第一次成功加载了模块。
- 然后您 运行 完成其余代码,但这次它在第二次导入时出现分段错误。这是因为您不能以这种方式重新加载模块。您需要改用
PyImport_ReloadModule()
。 - 即使进行了该修复,您仍会发现无法加载标准库。那是因为您已经删除了系统路径的其余部分。您需要遵循建议 here.
所以,修复是:
- 使用
std::string
而不是std::wstring
(对于 Python 2.x)。 - 重新加载模块时使用
PyImport_ReloadModule()
。 - 确保在设置路径时包含完整的 sys.path。
- 检查你的错误 - 对于大多数问题,我使用
PyErr_Print()
得到了明确的模块导入错误。