PyImport_ImportModule и оператор импорта загружаются в другое пространство имен? - PullRequest
6 голосов
/ 03 ноября 2011

Вот канонический пример программы , расширяющей встроенный Python 3.x в 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 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) для импорта через C API вызова Python 3, то строка (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__() функция вызывается оператором импорта.

Возможно, я допустил ошибку, предполагая, что PyImport_ImportModule является эквивалентом один к одному, и я должен использовать PyImport_ImportModuleEx с правильными (что именно?) Глобальными и локальными значениями, поэтому мой 'emb' находится в глобальном пространство имен моего встроенного интерпретатора.

1 Ответ

8 голосов
/ 03 ноября 2011

__import__ вообще не помещает модуль в какое-либо пространство имен, а возвращает его. import вызывает __import__, плюс он сохраняет результат в переменной. документы говорят, что import spam делает что-то похожее на:

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

Чтобы получить тот же эффект в C API, вам нужно присвоить глобальный emb. Другими словами, установите атрибут emb в модуле __main__.

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