PyImport_ImportModule,可以从内存中加载模块吗?

Posted

技术标签:

【中文标题】PyImport_ImportModule,可以从内存中加载模块吗?【英文标题】:PyImport_ImportModule, possible to load module from memory? 【发布时间】:2016-10-03 00:03:49 【问题描述】:

我在我的 C++ 程序中嵌入了 python。

我使用 PyImport_ImportModule 加载我写在 .py 文件中的模块。 但是我怎样才能从内存中加载它呢?假设我的 .py 文件是加密的,所以我需要先解密它并将代码提供给 python 执行。

此外,如果我可以绕过/拦截或修改导入机制,那就太好了,这样就不会从文件系统加载模块,而是从我自己的内存块加载,我该如何/可以这样做?

【问题讨论】:

【参考方案1】:

以下示例显示如何从 C 字符串定义模块:

#include <stdio.h>
#include <Python.h>
int main(int argc, char *argv[])

    Py_Initialize();
    PyRun_SimpleString("print('hello from python')");

    // fake module
    char *source = "__version__ = '2.0'";
    char *filename = "test_module.py";

    // perform module load
    PyObject *builtins = PyEval_GetBuiltins();
    PyObject *compile = PyDict_GetItemString(builtins, "compile");
    PyObject *code = PyObject_CallFunction(compile, "sss", source, filename, "exec");
    PyObject *module = PyImport_ExecCodeModule("test_module", code);

    PyRun_SimpleString("import test_module; print(test_module.__version__)");

    Py_Finalize();
    return 0;

输出:

hello from python
version: 2.0

您可以在文档中了解import hooks。您将需要使用find_moduleload_module 方法定义一个类。像下面这样的东西应该可以工作:

PyObject* find_module(PyObject* self, PyObject* args) 
    // ... lookup args in available special modules ...
    return Py_BuildValue("B", found);


PyObject* load_module(PyObject* self, PyObject* args) 
    // ... convert args into filname, source ...
    PyObject *builtins = PyEval_GetBuiltins();
    PyObject *compile = PyDict_GetItemString(builtins, "compile");
    PyObject *code = PyObject_CallFunction(compile, "sss", source, filename, "exec");
    PyObject *module = PyImport_ExecCodeModule("test_module", code);
    return Py_BuildValue("O", module);


static struct PyMethodDef methods[] = 
     "find_module", find_module, METH_VARARGS, "Returns module_loader if this is an encrypted module",
     "load_module", load_module, METH_VARARGS, "Load an encrypted module" ,
     NULL, NULL, 0, NULL 
;

static struct PyModuleDef modDef = 
    PyModuleDef_HEAD_INIT, "embedded", NULL, -1, methods, 
    NULL, NULL, NULL, NULL
;

static PyObject* PyInit_embedded(void)

    return PyModule_Create(&modDef);


int main() 
    ...
    PyImport_AppendInittab("embedded", &PyInit_embedded);
    PyRun_SimpleString("\
import embedded, sys\n\
class Importer:\n\
    def find_module(self, fullpath):\n\
        return self if embedded.find_module(fullpath) else None\n\
    def load_module(self, fullpath):\n\
        return embedded.load_module(fullpath)\n\
sys.path_hooks.insert(0, Importer())\n\
");
    ...

【讨论】:

以上是关于PyImport_ImportModule,可以从内存中加载模块吗?的主要内容,如果未能解决你的问题,请参考以下文章

C调用python——PyImport_ImportModule返回空指针

PyImport_ImportModule 和 import 语句是不是加载到不同的命名空间中?

Julia Plots: PyCall.PyError("PyImport_ImportModule\n\npyimport 找不到 Python 包 matplotlib.pyplot

python boost scope导致NoneType错误

Python 的 C API 的 const 正确性

如何在 C++ 程序将使用的 Python 脚本中导入 cpython 模块?