Назначение и использование PyModule_New

На первый взгляд, функции C-API PyModule_New и PyModule_NewObject, очевидно, создают новый объект модуля.

В официальной документации по Python приводится следующее объяснение PyModule_NewObject:

Возвращает новый объект модуля с атрибутом name, для которого установлено значение name. Заполняются только атрибуты модуля doc и name; вызывающая сторона отвечает за предоставление атрибута file.

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?


person Channel72    schedule 31.03.2013    source источник


Ответы (1)


PyModule_New — это конструктор для объектов модуля. Он также подвергается воздействию чистого кода Python, как метод __new__ класса 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 по имени.

person Blckknght    schedule 31.03.2013