代码之家  ›  专栏  ›  技术社区  ›  Elias Bachaalany

如何使用C API按文件的完整路径导入文件?

  •  4
  • Elias Bachaalany  · 技术社区  · 14 年前

    pyobject*pyimport_importmodule(const char*name)

    如何指定完整的文件路径和模块名?

    喜欢 PyImport_SomeFunction(const char *path_to_script, const char *name)

    谢谢, 伊莱亚斯

    6 回复  |  直到 7 年前
        1
  •  3
  •   AlexP    12 年前

    当所有的*.py文件都在一个目录中时,另一种解决方案是:

    PySys_SetPath("path/with/python/files");
    PyObject *pModule = PyImport_ImportModule("filename_without_extension");
    
        2
  •  2
  •   inklesspen    14 年前

    我不能给你一个完整的答案,但我想我可以给你一个开始的地方。python提供了一个内置模块,名为 imp 它提供了对导入内部构件的访问。它包括一个函数load_module(),允许您通过一个路径。这是在 Python/import.c ;只搜索 imp_load_module .

        3
  •  2
  •   stesim    11 年前

    正如所指出的,使用上面的Alexp解决方案,您不能在指定目录之外导入任何模块。但是,不是 设置 这条路,你可以 添加 要搜索模块的路径。这可以通过将该路径附加到 sys.path . 不幸的是,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>" );
    

    要引用当前目录,只需使用 "." 作为文件夹路径。

        4
  •  1
  •   Elias Bachaalany    14 年前

    最后,我使用了IMP模块的加载源:

    s.sprintf( 
      "import imp\n" 
      "imp.load_source('%s', r'%s')", modname, script_path); 
    PyRun_SimpleString(s.c_str()); 
    

    我认为这是最可行的解决方案。欢迎提出其他建议。

        5
  •  1
  •   zneak    9 年前

    塞顿会的 not hesitate 通过呼叫 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;
    }
    

    我写这个是基于 one of my projects' Python module loader ,它使用更高级的refcount管理,我还没有尝试过这个,所以使用风险由您自己承担。

        6
  •  0
  •   justwellbrock    7 年前

    我证实了 stesim 作品。

    不管使用哪种解决方案,重要的是要指出,在Windows上,使用带斜杠的完整路径而不是反斜杠是很重要的。

    path = "C:\\path\\to\\module\\module.py" // wrong
    path = "C:/path/to/module/module.py"     // correct
    

    在其他一些问题和答案中(比如 Windows path in python )有人说,第一个变体也应该起作用。不管我用什么方法,我都不能让它那样工作。