Как включить __build_class__ при создании модуля в Python C API

Я пытаюсь использовать Python 3.5 C API для выполнения некоторого кода, который включает создание учебный класс. В частности это:

class MyClass:
    def test(self):
        print('test')

MyClass().test()

Проблема у меня в том, что это ошибки, как это:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
NameError: __build_class__ not found

Итак, каким-то образом мне нужно, чтобы мой модуль включал __build_class__, но я не уверен, как это сделать (думаю, я бы также пропустил другие вещи, которые вы получаете по умолчанию при использовании Python тоже) - есть ли способ включить все эти встроенные функции в мой модуль?

Вот мой код:

#include <Python.h>

int main(void)
{
    int ret = 0;
    PyObject *pValue, *pModule, *pGlobal, *pLocal;

    Py_Initialize();

    pGlobal = PyDict_New();
    pModule = PyModule_New("mymod");
    pLocal = PyModule_GetDict(pModule);

    pValue = PyRun_String(
        "class MyClass:\n\tdef test(self):\n\t\tprint('test')\n\nMyClass().test()",
        Py_file_input,
        pGlobal,
        pLocal);

    if (pValue == NULL) {
        if (PyErr_Occurred()) {
            PyErr_Print();
        }
        ret = 1;
    } else {
        Py_DECREF(pValue);
    }

    Py_Finalize();

    return ret;
}

так что pValue это NULL и он звонит PyErr_Print.


person kmp    schedule 12.10.2016    source источник
comment
Я думаю, вам нужно передать глобальные переменные интерпретатора вместо пустого словаря. Но я не вижу, как это сделать.   -  person DavidW    schedule 12.10.2016
comment
На самом деле, вероятно, см. stackoverflow.com/a/25907027/4657412   -  person DavidW    schedule 12.10.2016
comment
Спасибо, к сожалению PyEval_GetGlobals(); возвращает null (я получаю SystemError: PyEval_EvalCodeEx: глобальные значения NULL из вызова). Нужно ли мне импортировать модуль main или что-то в этом роде?   -  person kmp    schedule 12.10.2016
comment
Ааа, благодаря вашей подсказке я начал искать GetGlobals возвращает null и нашел это: gossamer-threads.com/lists/python/python/8946#8946 - кажется, мне нужно сделать pGlobal = PyModule_GetDict(PyImport_AddModule(main)); (вместо pGlobal = PyDict_New()), и тогда это работает. (в этом основном подчеркивание, а не жирный) СПАСИБО!   -  person kmp    schedule 12.10.2016
comment
Рад, что указал вам на правильный путь. (Я не уверен, что сам получил бы полезный ответ). Кстати, вы можете поместить код в комментарии с обратными кавычками (`)   -  person DavidW    schedule 12.10.2016


Ответы (1)


Кажется, это (по крайней мере) два способа решить эту проблему...

Способ 1

Вместо:

pGlobal = PyDict_New();

Вы можете импортировать модуль __main__ и получить его глобальный словарь следующим образом:

pGlobal = PyModule_GetDict(PyImport_AddModule("__main__"));

Этот способ описывается так:

НО PyEval_GetGlobals вернет null, если он не вызывается из Python. Это никогда не произойдет при расширении Python, но когда Python встроен, это может произойти. Это связано с тем, что PyRun_* определяет глобальную область видимости, поэтому, если вы каким-то образом не находитесь внутри вещи PyRun_ (например, модуль, вызываемый из python, вызываемый из Embedder), глобальных переменных нет.

В ситуации со встроенным Python, если вы решите, что все ваши вызовы PyRun_* будут использовать __main__ в качестве глобального пространства имен, PyModule_GetDict(PyImport_AddModule("__main__")) сделает это.

Который я получил из вопроса встраивания, который я нашел на этом список Python.

Способ 2

Или в качестве альтернативы, которую я лично предпочитаю импортировать основной модуль (и нашел здесь), вы можете сделать это, чтобы заполнить новый словарь, который вы создали со встроенным материалом, который включает __build_class__:

pGlobal = PyDict_New();
PyDict_SetItemString(pGlobal, "__builtins__", PyEval_GetBuiltins());
person kmp    schedule 12.10.2016