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

Posted

技术标签:

【中文标题】PyImport_ImportModule 和 import 语句是不是加载到不同的命名空间中?【英文标题】:Do PyImport_ImportModule and import statement load into different namespace?PyImport_ImportModule 和 import 语句是否加载到不同的命名空间中? 【发布时间】:2011-12-21 09:06:09 【问题描述】:

这里是 C/C++ 程序 extending embedded 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

我想了解这两种导入方式之间的区别。 他们是否将模块导入不同的namespaces / scopes?

Python 3 文档引导我走上了这条道路:

    PyImport_ImportModule最好参考Python内置函数__import__()来描述 __import__() 函数由 import 语句调用。

也许我犯了一个错误,假设 PyImport_ImportModule 是一对一等价的,我应该将 PyImport_ImportModuleEx 与正确的(究竟是哪个?)全局变量和局部变量一起使用,所以我的“emb”位于我嵌入式的全局命名空间中口译员。

【问题讨论】:

【参考方案1】:

__import__ 根本不将模块放在任何命名空间中,而是返回它。 import 调用__import__,并将结果存储在一个变量中。 docs 说 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) */

【讨论】:

+1 有效!我明白我的误解在哪里了。重新未经测试的代码,只是“emb”需要用 PyUnicode_FromString(“emb”) 包装。我还注意到获取 main 的快捷方式:PyObject* main_module = PyImport_AddModule("main"); 已编辑,谢谢。我使用了PyObject_SetAttrString 而不是PyUnicode_FromString(更短,不用担心管理引用)。 我认为 PyImport_AddModule 的返回值是一个借用的引用,所以你不应该贬低它。

以上是关于PyImport_ImportModule 和 import 语句是不是加载到不同的命名空间中?的主要内容,如果未能解决你的问题,请参考以下文章

PyImport_ImportModule("PyQt4.QtGui") 失败

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

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

python boost scope导致NoneType错误

Python 的 C API 的 const 正确性

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