Загружаются ли PyImport_ImportModule и операторы импорта в разные пространства имен?

#c #python #import #python-c-api #python-embedding

#c #python #импорт #python-c-api #python-встраивание

Вопрос:

Вот канонический пример программы, расширяющей встроенный 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(amp;EmbModule);
}
//// Embedded Python with 'emb' loaded ////////////////////
int main()
{
    PyImport_AppendInittab("emb", amp;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) работает 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__() функция вызывается оператором import .

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

Ответ №1:

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

Комментарии:

1. 1 Работает! Я вижу, где было мое недоразумение. Повторно непроверенный код, просто «emb» нужно обернуть PyUnicode_FromString(«emb»). Я также заметил, что есть ярлык для получения main : PyObject* main_module = PyImport_AddModule(» main «);

2. Отредактировано, спасибо. Я использовал PyObject_SetAttrString вместо PyUnicode_FromString (короче, меньше беспокоясь об управлении ссылками).

3. Я думаю, что возвращаемое значение из PyImport_AddModule является заимствованной ссылкой, поэтому вам не следует ее уменьшать.