从Python C API中的字符串导入模块

时间:2016-10-01 15:45:06

标签: python c python-c-api cross-language

使用带有PyImport_Import()的Python C API从文件导入Python模块相对容易,但我需要使用存储在字符串中的函数。有没有办法从字符串导入python模块(澄清:没有文件;代码是在一个字符串中)还是我必须将字符串保存为临时文件?

3 个答案:

答案 0 :(得分:2)

无需使用临时文件。使用此代码:

const char *MyModuleName = "blah";
const char *MyModuleCode = "print 'Hello world!'";
PyObject *pyModule = PyModule_New(MyModuleName);
// Set properties on the new module object
PyModule_AddStringConstant(pyModule, "__file__", "");
PyObject *localDict = PyModule_GetDict(pyModule);   // Returns a borrowed reference: no need to Py_DECREF() it once we are done
PyObject *builtins = PyEval_GetBuiltins();  // Returns a borrowed reference: no need to Py_DECREF() it once we are done
PyDict_SetItemString(localDict, "__builtins__", builtins);

// Define code in the newly created module
PyObject *pyValue = PyRun_String(MyModuleCode, Py_file_input, localDict, localDict);
if (pyValue == NULL) {
    // Handle error
}
else
    Py_DECREF(pyValue);

这是从真实的商业应用程序中获取的代码(我通过删除错误处理和其他不需要的细节稍微修改了它)。 只需在MyModuleName中设置所需的模块名称,在MyModuleCode中设置Python代码即可完成!

答案 1 :(得分:1)

如果我的理解是正确的,您可以使用PyImport_ImportModuleconst char* name指定要导入的模块。

由于我的理解不正确:

通常最好将内容转储到.py文件,然后使用PyRun_File执行它们,但是,如果您有字符串并希望使用我猜 >您可以使用Py_CompileString将其编译为代码对象,然后将其提供给PyEval_EvalCode进行评估。

答案 2 :(得分:0)

按照Dimitirs制定的策略,我取得了成功。

            Py_Initialize();
            PyObject *module = Py_CompileString(
                // language: Python
                R"EOT(
fake_policy = {
      "maxConnections": 4,
      "policyDir": "/tmp",
      "enableVhostPolicy": True,
      "enableVhostNamePatterns": False,
})EOT",
                "test_module", Py_file_input);
            REQUIRE(module != nullptr);

            PyObject *pModuleObj = PyImport_ExecCodeModule("test_module", module);
            REQUIRE(pModuleObj != nullptr);
            // better to check with an if, use PyErr_Print() or such to read the error

            PyObject *pAttrObj = PyObject_GetAttrString(pModuleObj, "fake_policy");
            REQUIRE(pAttrObj != nullptr);

            auto *entity = reinterpret_cast<qd_entity_t *>(pAttrObj);
            REQUIRE(qd_entity_has(entity, "enableVhostNamePatterns"));  // sanity check for the test input

            // call Py_DecRef s

在撰写本文时,我使用https://awasu.com/weblog/embedding-python/calling-python-code-from-your-program/作为另一个参考。