В двух последних разделах мы занимались выполнением строк программного кода, но программы на C могут также легко работать с объектами Python. Программа в примере 20.27 выполняет ту же задачу, что и примеры 20.23 и 20.26, но использует другие инструменты API для прямого взаимодействия с объектами в модуле Python:
PyImport_ImportModule
Импортирует модуль в C, как и прежде.
PyObject_GetAttrString
Загружает значение атрибута объекта по имени.
PyEval_CallObject
Вызывает функцию Python (или класс, или метод).
PyArg_Parse
Преобразует объекты Python в значения C.
Py_BuildValue
Преобразует значения С в объекты Python.
С обеими функциями преобразования мы познакомились ранее в этой главе. Вызов функции PyEval_CallObject в этой версии является ключевым: он выполняет импортированную функцию, передавая ей кортеж аргументов подобно синтаксической конструкции func(*args) в языке Python. Значение, возвращаемое функцией Python, поступает в C в виде PyObject*, обобщенного указателя на объект Python.
Пример 20.27. PP4E\Integrate\Embed\Basics\embed-object.c
/* получает и вызывает объекты из модулей */
#include <Python.h>
main() {
char *cstr;
PyObject *pstr, *pmod, *pfunc, *pargs;
printf("embed-object\n");
Py_Initialize();
/* получить usermod.message */
Mpmod = PyImport_ImportModule("usermod");
pstr = PyObject_GetAttrString(pmod, "message");
/* преобразовать строку в C */
PyArg_Parse(pstr, "s", &cstr);
printf("%s\n", cstr);
Py_DECREF(pstr);
/* вызвать usermod.transform(usermod.message) */
pfunc = PyObject_GetAttrString(pmod, "transform");
pargs = Py_BuildValue("(s)", cstr);
pstr = PyEval_CallObject(pfunc, pargs);
PyArg_Parse(pstr, "s", &cstr);
printf("%s\n", cstr);
/* освободить объекты */
Py_DECREF(pmod);
Py_DECREF(pstr);
Py_DECREF(pfunc); /* в main() это делать необязательно */ Py_DECREF(pargs); /* поскольку вся память и так освобождается */ Py_Finalize();
}
После компиляции и выполнения получается тот же результат:
…/PP4E/Integrate/Embed/Basics$ ./embed-object embed-object
The meaning of life…
THE MEANING OF PYTHON…
Но на этот раз весь вывод создается средствами языка C — сначала путем получения значения атрибута message модуля Python, а затем путем прямого извлечения и вызова объекта функции transform модуля и вывода возвращаемого им значения, пересылаемого в C. Входными данными функции transform является аргумент функции, а не глобальная переменная, которой предварительно присвоено значение. Обратите внимание, что на этот раз message извлекается как атрибут модуля, а не в результате выполнения строки программного кода с именем переменной; часто есть несколько способов получить один и тот же результат, используя разные функции API.
Вызов функций в модулях, как показано в этом примере, дает простой способ организации встраивания. Программный код в файле модуля можно произвольно менять, не перекомпилируя выполняющую его программу на C. Обеспечивается также модель прямой связи: входные и выходные данные могут иметь вид аргументов функций и возвращаемых значений.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011