1

PyModule_New从表面上看,C-API 函数PyModule_NewObject显然创建了一个新的模块对象。

官方 Python 文档提供了以下解释PyModule_NewObject

返回一个name属性设置为 name 的新模块对象。只填写模块的docname属性;调用者负责提供文件属性。

PyModule_New做同样的事情,除了它接受一个 C 字符串 ( char*) 作为模块名称的参数,而不是一个PyObject*字符串。

好的,这很简单,但是...

我的问题是:调用 API 函数有什么用PyModule_NewObject

当然,理论上这对于您想要动态创建新模块的情况来说会很棒。但问题是,实际上,在创建一个新的模块对象之后,对其有用的唯一方法是将对象(如方法、类、变量等)添加到模块的__dict__属性中。这样,模块的用户可以导入它并实际使用它。

问题是__dict__模块的属性是只读的

>>> import re
>>> x = re
>>> re.__dict__ = { "foo" : "bar" }
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: readonly attribute


所以,在实践中,就我所见,动态创建的模块真的没有办法做任何有用的事情。那么,C API 函数的目的是PyModule_New什么?

4

1 回答 1

2

PyModule_New是模块对象的构造函数。__new__作为类的方法,它也暴露给纯 Python 代码types.ModuleType

用户代码可能很少需要使用其中任何一个,因为您通常通过导入它们来获取模块。但是,Python 解释器使用的机制PyModule_New在请求导入时用于生成模块对象。

您可以import.c在 Python 源代码中看到这一点:

/* Get the module object corresponding to a module name.
First check the modules dictionary if there's one there,
if not, create a new one and insert it in the modules dictionary.
Because the former action is most common, THIS DOES NOT RETURN A
'NEW' REFERENCE! */

PyImport_AddModule(const char *name)
{
    PyObject *modules = PyImport_GetModuleDict();
    PyObject *m;

    if ((m = PyDict_GetItemString(modules, name)) != NULL &&
        PyModule_Check(m))
        return m;
    m = PyModule_New(name);
    if (m == NULL)
        return NULL;
    if (PyDict_SetItemString(modules, name, m) != 0) {
        Py_DECREF(m);
        return NULL;
    }
    Py_DECREF(m); /* Yes, it still exists, in modules! */

    return m;
}

至于如何在新的模块对象中设置值,您可以使用常规属性访问。在 Python 代码(而不是 C)中,这很简单:

import types

mymodule = types.ModuleType("mymodule")
mymodule.foo = "foo"

请注意,除非您做一些额外的工作,否则无法将这种方式创建的模块导入其他任何地方。例如,您可以将其添加到模块查找字典中sys.modules

import sys

sys.modules["mymodule"] = mymodule

现在其他模块可以按名称导入mymodule

于 2013-03-31T04:30:12.643 回答