【问题标题】:How to import a file by its full path using C api?如何使用 C api 通过完整路径导入文件?
【发布时间】:2009-11-25 13:31:25
【问题描述】:
PyObject* PyImport_ImportModule( const char *name) 

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

点赞PyImport_SomeFunction(const char *path_to_script, const char *name)

【问题讨论】:

    标签: python python-c-api


    【解决方案1】:

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

    PySys_SetPath("path/with/python/files");
    PyObject *pModule = PyImport_ImportModule("filename_without_extension");
    

    【讨论】:

    • 警告,PySys_SetPath 会覆盖路径变量,您的目标 python 脚本可能无法导入其模块。你应该更喜欢那个解决方案:stackoverflow.com/questions/35137145/…
    • 这里的评论比答案更有用
    【解决方案2】:

    正如所指出的,使用 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 );
    

    现在您可以使用通常的方式导入任何文件&lt;insert folder path&gt;/&lt;file&gt;.py

    PyObject* mymodule = PyImport_ImportModule( "<file>" );
    

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

    【讨论】:

      【解决方案3】:

      最终,我最终使用了 imp 模块中的 load_source:

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

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

      【讨论】:

        【解决方案4】:

        我不能给你一个完整的答案,但我想我可以给你一个起点。 Python 提供了一个名为 imp 的内置模块,它提供对导入内部的访问。它包括一个函数 load_module() ,它可以让你传入一个路径。这是在Python/import.c 中实现的;只需搜索imp_load_module

        【讨论】:

          【解决方案5】:

          CPython 将通过not hesitate 调用imp 模块来执行导入作业,因此您没有理由不自己做。

          这是在 C++ 中执行此操作的一种方法,其中 modulePathmoduleName 由于懒惰是单独的变量:

          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写的,它使用了更高级的引用计数管理,我还没有尝试过,所以使用风险自负。

          【讨论】:

            【解决方案6】:

            我验证了stesim 的替代方法有效。

            无论使用哪种解决方案,重要的是要提到在 Windows 上使用斜杠而不是反斜杠的完整路径很重要。

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

            在其他一些问题和答案(如Windows path in python)中指出,第一个变体也应该起作用。无论我尝试什么方法,我都无法让它以这种方式工作。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-12-30
              • 1970-01-01
              • 2014-06-08
              • 2017-02-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多