Язык программирования Python
Шрифт:
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
0, /*tp_xxx4*/
md5type_doc, /*tp_doc*/
};
// Функции модуля md5:
// Функция new для получения нового объекта типа md5type
static PyObject *
MD5_new(PyObject *self, PyObject *args)
{
md5object *md5p;
unsigned char *cp = NULL;
int len = 0;
// Разбор параметров.
// в строке формата означает окончание
// списка обязательных параметров.
// Остальное — как и выше: s# - строка, после : — имя
if (!PyArg_ParseTuple(args, "|s#:new», &cp, &len))
return NULL;
if ((md5p = newmd5object) == NULL)
return NULL;
// Если был задан параметр cp:
if (cp)
MD5Update(&md5p->md5, cp, len);
return (PyObject *)md5p;
}
// Строка документации для new
PyDoc_STRVAR(new_doc, «new([arg]) -> md5 object …»);
// Список функций, которые данный модуль экспортирует
static PyMethodDef md5_functions[] = {
{«new», (PyCFunction)MD5_new, METH_VARARGS, new_doc},
{«md5», (PyCFunction)MD5_new, METH_VARARGS, new_doc},
{NULL, NULL} /* Sentinel */
};
// Следует заметить, что md5 — то же самое, что new. Эта функция оставлена для
// обратной совместимости со старым модулем md5
// Инициализация модуля
PyMODINIT_FUNC
initmd5(void)
{
PyObject *m, *d;
MD5type.ob_type = &PyType_Type;
// Инициализируется модуль
m = Py_InitModule3(«md5», md5_functions, module_doc);
// Получается словарь с именами модуля
d = PyModule_GetDict(m);
// Добавляется атрибут MD5Type (тип md5–объекта) к словарю
PyDict_SetItemString(d, «MD5Type», (PyObject *)&MD5type);
// Добавляется целая константа digest_size к модулю
PyModule_AddIntConstant(m, «digest_size», 16);
}
На основе этого примера можно строить собственные модули расширения, ознакомившись с документацией по C/API и документом «Extending and Embedding» («Расширение и встраивание») из стандартной поставки Python. Перед тем, как приступать к созданию своего модуля, следует убедиться, что это целесообразно: подходящего модуля еще не создано и реализация в виде чистого Python неэффективна. Если создан действительно полезный модуль, его можно предложить для включения в поставку Python. Для этого нужно просто связаться с кем–нибудь из разработчиков по электронной почте или предложить модуль в виде «патча» через http://sourceforge.net.
Пример встраивания интерпретатора в программу на C
Интерпретатор Python может быть встроен в программу на C с использованием C API. Это лучше всего демонстрирует уже работающий пример:
Листинг
/* File : demo.c */
/*
#include «Python.h»
main(int argc, char **argv)
{
/* Передает argv[0] интерпретатору Python */
Py_SetProgramName(argv[0]);
/* Инициализация интерпретатора */
Py_Initialize;
/* … */
/* Выполнение операторов Python (как бы модуль __main__) */
PyRun_SimpleString(«import time\n»);
PyRun_SimpleString(«print time.localtime(time.time)\n»);
/* … */
/* Завершение работы интерпретатора */
Py_Finalize;
}
Компиляция этого примера с помощью компилятора gcc может быть выполнена, например, так:
Листинг
ver=«2.3»
gcc–fpic demo.c–DHAVE_CONFIG_H–lm–lpython${ver} \
— lpthread–lutil–ldl \
— I/usr/local/include/python${ver} \
— L/usr/local/lib/python${ver}/config \
— Wl, — E \
— o demo
Здесь следует отметить следующие моменты:
программу необходимо компилировать вместе с библиотекой libpython соответствующей версии (для этого используется опция–l, за которой следует имя библиотеки) и еще с библиотеками, которые требуются для Python: libpthread, libm, libutil и т.п.)
опция pic порождает код, не зависящий от позиции, что позволяет в дальнейшем динамически компоновать код
обычно требуется явно указать каталог, в котором лежит заголовочный файл Python.h (в gcc это делается опцией–I)
чтобы получившийся исполняемый файл мог корректно предоставлять имена для динамически загружаемых модулей, требуется передать компоновщику опцию–E: это можно сделать из gcc с помощью опции–Wl, — E. (В противном случае, модуль time, а это модуль расширения в виде динамически загружаемого модуля, не будет работать из–за того, что не увидит имен, определенных в libpython)
Здесь же следует сделать еще одно замечание: программа, встраивающая Python, не должна много раз выполнять Py_Initialize и Py_Finalize, так как это может приводить к утечке памяти. Сам же интерпретатор Python очень стабилен и в большинстве случаев не дает утечек памяти.
Использование SWIG
SWIG (Simplified Wrapper and Interface Generator, упрощенный упаковщик и генератор интерфейсов) - это программное средства, сильно упрощающее (во многих случаях — автоматизирующее) использование библиотек, написанных на C и C++, а также на других языках программирования, в том числе (не в последнюю очередь!) на Python. Нужно отметить, что SWIG обеспечивает достаточно полную поддержку практически всех возможностей C++, включая предобработку, классы, указатели, наследование и даже шаблоны C++. Последнее очень важно, если необходимо создать интерфейс к библиотеке шаблонов.