Как импортировать файл по полному пути с помощью C API?

StackOverflow https://stackoverflow.com/questions/1796925

  •  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) утверждается, что первый вариант тоже должен работать.Я не мог заставить его работать таким образом, какой бы метод я ни пробовал.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top