Вызовите несколько функций Python из разных каталогов

У меня есть некоторый код, который будет идти в каталог (папка 1 для демонстрационных целей), а затем вызвать функцию под названием function в файле python_function.py, Код выглядит так:

#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'

4

Решение

РЕДАКТИРОВАТЬ: Обновлено с дальнейшими ответами на найденные ошибки.

Вы не можете импортировать свой модуль в выходные данные отладки. При запуске вне отладчика вы сталкиваетесь с проблемой, которую вы не можете просто импортировать, с помощью того же вызова импорта. Полная цепочка проблем примерно такая.

При отладке:

  1. Ваш отладчик не устанавливает правильный текущий рабочий каталог.
  2. Относительный путь недействителен, но принимается PySys_SetPath(),
  3. Поэтому вы получаете NULL от PyImport_Import() указывает на то, что импорт не удается (как задокументировано Вот под отладчиком.
  4. Поскольку вы не проверяете наличие ошибок, вы передаете NULL в следующую функцию, которая пытается разыменовать указатель и завершается с ошибкой сегментации.

Я столкнулся с проблемой с Python2.7 (используя char * вместо wchar * — как описано в комментариях ниже). Поместив это в сторону, когда работает нормально:

  1. Относительный путь действителен и принят PySys_SetPath(),
  2. Поэтому вам удастся загрузить модуль с первого раза.
  3. Затем вы пробегаете оставшуюся часть кода, но на этот раз происходит сбой сегментации при втором импорте. Это потому, что вы не можете перезагрузить модуль таким образом. Вам нужно использовать PyImport_ReloadModule() вместо.
  4. Даже с этим исправлением вы обнаружите, что не можете загружать стандартные библиотеки. Это потому, что вы удалили оставшуюся часть системного пути. Вы должны следовать совету Вот.

Итак, исправления:

  1. использование std::string вместо std::wstring (для Python 2.x).
  2. использование PyImport_ReloadModule() при перезагрузке модулей.
  3. Убедитесь, что вы указали полный путь sys.path при настройке вашего пути.
  4. Проверьте ваши ошибки — я получил явные ошибки импорта модуля, используя PyErr_Print() для большинства проблем.
4

Другие решения


По вопросам рекламы [email protected]