Как импортировать файл по полному пути с помощью C API?
-
22-09-2019 - |
Вопрос
PyObject* PyImport_ImportModule(const char *name)
Как вместо этого указать полный путь к файлу и имя модуля?
Нравиться PyImport_SomeFunction(const char *path_to_script, const char *name)
Спасибо, Элиас
Решение 4
В конце концов я использовал модуль load_source из модуляimp:
s.sprintf(
"import imp\n"
"imp.load_source('%s', r'%s')", modname, script_path);
PyRun_SimpleString(s.c_str());
Я считаю, что это наиболее реальное решение.Другие предложения приветствуются.
Другие советы
Другое решение для случаев, когда все файлы *.py находятся в одном каталоге:
PySys_SetPath("path/with/python/files");
PyObject *pModule = PyImport_ImportModule("filename_without_extension");
Я не могу дать вам полный ответ, но думаю, что могу дать вам точку для начала.Python предоставляет встроенный модуль под названием imp
который обеспечивает доступ к внутренним компонентам импорта.Он включает функцию load_module(), которая позволяет передавать путь.Это реализовано в Python/import.c;просто найди imp_load_module
.
Как уже отмечалось, используя приведенное выше решение AlexP, вы не можете импортировать какие-либо модули за пределы указанного каталога.Однако вместо параметр путь, ты можешь добавлять путь, по которому нужно искать модули.Это можно сделать, добавив этот путь в системный путь.К сожалению, C API не предоставляет функцию, которая могла бы сделать это напрямую.Вместо этого вы можете попросить Python сделать это, используя
PyRun_SimpleString( "import sys\nsys.path.append(\"<insert folder path>\")\n" );
или любой эквивалент, например: (предупреждение:непроверенный)
PyObject* sys = PyImport_ImportModule( "sys" );
PyObject* sys_path = PyObject_GetAttrString( sys, "path" );
PyObject* folder_path = PyUnicode_FromString( "<insert folder path>" );
PyList_Append( sys_path, folder_path );
Теперь вы можете импортировать любой файл <insert folder path>/<file>.py
используя обычный
PyObject* mymodule = PyImport_ImportModule( "<file>" );
Чтобы обратиться к текущему каталогу, просто используйте "."
в качестве пути к папке.
CPython будет не стесняйтесь позвонить через imp
модуль для выполнения заданий импорта, поэтому нет причин, по которым вам не следует делать это самостоятельно.
Вот один из способов сделать это на C++, где modulePath
и moduleName
являются отдельными переменными из-за лени:
PyObject* loadModule(const char* modulePath, const char* moduleName)
{
auto modules = PyImport_GetModuleDict();
auto impModule = PyDict_GetItemString(modules, "imp");
if (impModule)
{
// GetItemString returns a borrowed reference, but ImportModule
// returns a new reference, so INCREF here to even it out
Py_INCREF(impModule);
}
else
{
impModule = PyImport_ImportModule("imp");
if (!impModule)
{
// we've tried hard enough, bail out
PyErr_Print();
return nullptr;
}
}
// The Python API asks for non-const char pointers :(
char methodName[] = "load_source";
char args[] = "ss";
auto module = PyObject_CallMethod(impModule, methodName, args, moduleName, modulePath);
Py_XDECREF(impModule);
Py_XDECREF(modulePath);
return module;
}
Я написал это на основе загрузчик модуля Python одного из моих проектов, который использует более сложное управление счетчиком ссылок, и я не пробовал его, поэтому используйте его на свой страх и риск.
Я проверил, что альтернатива стесим работает.
Независимо от того, какое решение используется, важно отметить, что в Windows важно иметь полный путь с косой чертой вместо обратной косой черты.
path = "C:\\path\\to\\module\\module.py" // wrong
path = "C:/path/to/module/module.py" // correct
В некоторых других вопросах и ответах (например, Путь Windows в Python) утверждается, что первый вариант тоже должен работать.Я не мог заставить его работать таким образом, какой бы метод я ни пробовал.