执行PyImport_ImportModule和import语句加载到不同的命名空间

Do PyImport_ImportModule and import statement load into different namespace?

本文关键字:命名空间 加载 语句 PyImport ImportModule import 执行      更新时间:2023-10-16

这是一个扩展嵌入式Python 3程序的典型示例。C/c++:

#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 embn");       // (1)
    //PyImport_ImportModule("emb");           // (2)
    PyRun_SimpleString("print(emb.foo())n"); // (3)
    Py_Finalize();
    return 0;
}

我将emb模块添加到嵌入式解释器的内置模块中。我还想自动导入它,这样用户就不必在提供给我的嵌入式解释器的脚本中发出import emb语句。我正在尝试两种导入方式,在(1)(2)行。

(1)工作,在(3)行的简单测试中可以找到没有显式导入的emb模块。但是,如果我注释掉(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. 来描述。
  3. __import__()函数被import语句调用。

也许我犯了一个错误,假设PyImport_ImportModule是一对一的等效,我应该使用PyImport_ImportModuleEx与正确的(确切地?)全局变量和局部变量,所以我的'emb'土地在我的嵌入式解释器的全局命名空间。

__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) */