我想创建一个嵌入式 python 3 解释器,并让 python 脚本导入通过 C Python API 创建的模块。

创建“顶级”模块没问题,但现在我想在包中组织我的模块......但我失败了。

这是我当前的(简单)代码:

#include <Python.h>

//// Definition of 'emb.sub' module
static PyObject* emb_sub_foo(PyObject *self, PyObject *args)
{
    char const* n = "I am sub foo";
    return Py_BuildValue("s", n);
}
static PyMethodDef EmbSubMethods[] = {
    {"foo", emb_sub_foo, METH_VARARGS, "Returns sub foo"},
    {NULL, NULL, 0, NULL}
};
static PyModuleDef EmbSubModule = {
    PyModuleDef_HEAD_INIT, "emb.sub", NULL, -1, EmbSubMethods,
    NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb_sub(void)
{
    return PyModule_Create(&EmbSubModule);
}

//// Embedded Python
int main()
{
    PyImport_AppendInittab("emb.emb", &PyInit_emb_sub);
    Py_Initialize();

    PyRun_SimpleString("import emb.sub\n");

    Py_Finalize();
    return 0;
}

当我执行程序时,我得到:
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named 'emb'

所以我创建了一个空的 emb 模块,并像这样设置它的 __path__:
#include <Python.h>

//// Definition of 'emb' module
static PyModuleDef EmbModule = {
    PyModuleDef_HEAD_INIT, "emb", NULL, -1, NULL,
    NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb(void)
{
    PyObject *mod = PyModule_Create(&EmbModule);
    PyModule_AddObject(mod, "__path__", Py_BuildValue("()"));

    return mod;
}

//// Definition of 'emb.sub' module
static PyObject* emb_sub_foo(PyObject *self, PyObject *args)
{
    char const* n = "I am sub foo";
    return Py_BuildValue("s", n);
}
static PyMethodDef EmbSubMethods[] = {
    {"foo", emb_sub_foo, METH_VARARGS, "Returns sub foo"},
    {NULL, NULL, 0, NULL}
};
static PyModuleDef EmbSubModule = {
    PyModuleDef_HEAD_INIT, "emb.sub", NULL, -1, EmbSubMethods,
    NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb_sub(void)
{
    return PyModule_Create(&EmbSubModule);
}

//// Embedded Python
int main()
{
    PyImport_AppendInittab("emb", &PyInit_emb);
    PyImport_AppendInittab("emb.sub", &PyInit_emb_sub);
    Py_Initialize();

    PyRun_SimpleString("import emb.sub\n");

    Py_Finalize();
    return 0;
}

现在我收到这个错误:
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named 'emb.sub'

我想知道是否可以在嵌入式 python 中创建包和模块的层次结构?

谢谢 !

最佳答案

据我所知,默认的内置模块处理无法与包+模块名称匹配。这可以通过添加一个自定义导入钩子(Hook)来解决,只需在 Py_Initialize() 之后运行它:

PyRun_SimpleString(
    "import importlib.abc\n" \
    "import importlib.machinery\n" \
    "import sys\n" \
    "\n" \
    "\n" \
    "class Finder(importlib.abc.MetaPathFinder):\n" \
    "    def find_spec(self, fullname, path, target=None):\n" \
    "        if fullname in sys.builtin_module_names:\n" \
    "            return importlib.machinery.ModuleSpec(\n" \
    "                fullname,\n" \
    "                importlib.machinery.BuiltinImporter,\n" \
    "            )\n" \
    "\n" \
    "\n" \
    "sys.meta_path.append(Finder())\n" \
);

我用你的完整代码成功地尝试了这个:
#include <Python.h>

//// Definition of 'emb' module
static PyModuleDef EmbModule = {
    PyModuleDef_HEAD_INIT, "emb", NULL, -1, NULL,
    NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb(void)
{
    PyObject *mod = PyModule_Create(&EmbModule);
    PyModule_AddObject(mod, "__path__", Py_BuildValue("()"));

    return mod;
}

//// Definition of 'emb.sub' module
static PyObject* emb_sub_foo(PyObject *self, PyObject *args)
{
    char const* n = "I am sub foo";
    return Py_BuildValue("s", n);
}
static PyMethodDef EmbSubMethods[] = {
    {"foo", emb_sub_foo, METH_VARARGS, "Returns sub foo"},
    {NULL, NULL, 0, NULL}
};
static PyModuleDef EmbSubModule = {
    PyModuleDef_HEAD_INIT, "emb.sub", NULL, -1, EmbSubMethods,
    NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb_sub(void)
{
    return PyModule_Create(&EmbSubModule);
}

//// Embedded Python
int main()
{
    PyImport_AppendInittab("emb", &PyInit_emb);
    PyImport_AppendInittab("emb.sub", &PyInit_emb_sub);
    Py_Initialize();

    PyRun_SimpleString(
        "import importlib.abc\n" \
        "import importlib.machinery\n" \
        "import sys\n" \
        "\n" \
        "\n" \
        "class Finder(importlib.abc.MetaPathFinder):\n" \
        "    def find_spec(self, fullname, path, target=None):\n" \
        "        if fullname in sys.builtin_module_names:\n" \
        "            return importlib.machinery.ModuleSpec(\n" \
        "                fullname,\n" \
        "                importlib.machinery.BuiltinImporter,\n" \
        "            )\n" \
        "\n" \
        "\n" \
        "sys.meta_path.append(Finder())\n" \
    );

    PyRun_SimpleString("import emb.sub\n");
    PyRun_SimpleString("print(emb.sub.foo())\n");

    Py_Finalize();
    return 0;
}

关于python - 在嵌入式python 3中以编程方式定义包结构,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39250524/

10-16 18:49
查看更多