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

8 投票
1 回答
5502 浏览
提问于 2025-04-17 05:35

这里有一个经典的例子,展示了如何在C/C++中扩展嵌入式的Python 3.x程序:

#include <Python.h>
//// Definition of 'emb' Python module ////////////////////
static PyObject* emb_foo(PyObject *self, PyObject *args)
{
    char const* n = "I am foo";
    return Py_BuildValue("s", n);
}
static PyMethodDef EmbMethods[] = {
    {"foo", emb_foo, METH_VARARGS, "Returns foo"},
    {NULL, NULL, 0, NULL}
};
static PyModuleDef EmbModule = {
    PyModuleDef_HEAD_INIT, "emb", NULL, -1, EmbMethods,
    NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb(void)
{
    return PyModule_Create(&EmbModule);
}
//// Embedded Python with 'emb' loaded ////////////////////
int main()
{
    PyImport_AppendInittab("emb", &PyInit_emb);
    Py_Initialize();

    PyRun_SimpleString("import emb\n");       // (1)
    //PyImport_ImportModule("emb");           // (2)

    PyRun_SimpleString("print(emb.foo())\n"); // (3)

    Py_Finalize();
    return 0;
}

我把emb模块添加到了嵌入式解释器的内置模块中。我还想让它自动导入,这样用户在给我的嵌入式解释器提供的脚本中就不需要手动输入import emb这条语句了。我尝试了两种导入方式,分别在(1)(2)行。

(1)的方式可以正常工作,emb模块可以在(3)行的简单测试中找到,而不需要明确导入。但是,如果我把(1)这一行注释掉,改用(2)这一行通过Python 3的C API来导入,那么(3)这一行就会出错:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
NameError: name 'emb' is not defined

我想了解这两种导入方式之间有什么区别。它们是否将模块导入到不同的命名空间/作用域中?

Python 3的文档让我沿着这个思路走:

  1. PyImport_ImportModule可以通过内置的Python函数__import__()来更好地理解。
  2. __import__()函数是由import语句调用的。

也许我犯了个错误,以为PyImport_ImportModule是完全等价的,其实我应该使用PyImport_ImportModuleEx,并提供正确的(具体是哪个?)全局和局部变量,这样我的'emb'才能正确地放入嵌入式解释器的全局命名空间中。

1 个回答

10

__import__ 这个东西不会把模块放到任何命名空间里,而是直接把它返回。import 会调用 __import__,并且把结果存储到一个变量里。文档上说,import spam 的效果和下面的代码差不多:

spam = __import__('spam', globals(), locals(), [], 0)

如果你想在 C API 中实现同样的效果,你需要给 emb 这个全局变量赋值。换句话说,就是要在 __main__ 模块上设置 emb 属性。

PyObject* emb_module = PyImport_ImportModule("emb");
PyObject* main_module = PyImport_AddModule("__main__");
PyObject_SetAttrString(main_module, "emb", emb_module);
Py_XDECREF(emb_module);
/* (main_module is a borrowed reference) */

撰写回答