Язык программирования Python.

Использование SWIG.

SWIG (Simplified Wrapper and Interface Generator, упрощенный упаковщик и генератор интерфейсов) — это программное средства, сильно упрощающее (во многих случаях — автоматизирующее) использование библиотек, написанных на C и C++, а также на других языках программирования, в том числе (не в последнюю очередь!) на Python. Нужно отметить, что SWIG обеспечивает достаточно полную поддержку практически всех возможностей C++, включая предобработку, классы, указатели, наследование и даже шаблоны C++. Последнее очень важно, если необходимо создать интерфейс к библиотеке шаблонов.

Пользоваться SWIG достаточно просто, если уметь применять компилятор и компоновщик (что в любом случае требуется при программировании на C/C++).

Простой пример использования SWIG.

Предположим, что есть программа на C, реализующая некоторую функцию (пусть это будет вычисление частоты появления различных символов в строке):

/* File : freq.c */

#include <stdlib.h>

Int * frequency(char s[]) {

 int *freq;

 char *ptr;

 freq = (int*)(calloc(256, sizeof(int)));

 if (freq != NULL).

  for (ptr = s; *ptr; ptr++).

   freq[*ptr] += 1;

 return freq;

}

Для того чтобы можно было воспользоваться этой функцией из Python, нужно написать интерфейсный файл (расширение .i) примерно следующего содержания:

/* File : freq.i */

%module freq.

%typemap(out) int * {

 int i;

 $result = PyTuple_New(256);

 for(i=0; i<256; i++).

  PyTuple_SetItem($result, i, PyLong_FromLong($1[i]));

 free($1);

}

Extern int * frequency(char s[]);

Интерфейсные файлы содержат инструкции самого SWIG и фрагменты C/C++-кода, возможно, с макровключениями (в примере выше: $result, $1). Следует заметить, что для преобразования массива целых чисел в кортеж элементов типа long, необходимо освободить память из–под исходного массива, в котором подсчитывались частоты.

Теперь (подразумевая, что используется компилятор gcc), создание модуля расширения может быть выполнено примерно так:

Swig–python freq.i.

Gcc–c–fpic freq_wrap.c freq.c -DHAVE_CONFIG_H \

-I/usr/local/include/python2.3 \

–I/usr/local/lib/python2.3/config.

Gcc–shared freq.o freq_wrap.o–o _freq.so.

После этого в рабочем каталоге появляется файлы _freq.so и freq.py, которые вместе и дают доступ к требуемой функции:

>>> import freq.

>>> freq.frequency("ABCDEF")[60:75].

(0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 0L).

Помимо этого, можно посмотреть на содержимое файла freq_wrap.c, который был порожден SWIG: в нем, среди прочих вспомогательных определений, нужных самому SWIG, можно увидеть что–то подобное проиллюстрированному выше примеру модуля md5. Вот фрагмент этого файла с определением обертки для функции frequency():

Extern int *frequency(char []);

Static PyObject *_wrap_frequency(PyObject *self, PyObject *args) {

 PyObject *resultobj;

 char *arg1;

 int *result;

 if(!PyArg_ParseTuple(args,(char *)"s:frequency",&arg1)) goto fail;

 result = (int *)frequency(arg1);

 {

  int i;

  resultobj = PyTuple_New(256);

  for(i=0; i<256; i++).

   PyTuple_SetItem(resultobj, i, PyLong_FromLong(result[i]));

  free(result);

 }

 return resultobj;

Fail:

 return NULL;

}

В качестве упражнения, предлагается сопоставить это определение с файлом freq.i и понять, что происходит внутри функции _wrap_frequency(). Подсказка: можно посмотреть еще раз комментарии к C–коду модуля md5.

Стоит еще раз напомнить, что в отличие от Python, в языке C/C++ управление памятью должно происходить в явном виде. Именно поэтому добавлена функция free() при преобразовании типа. Если этого не сделать, возникнут утечки памяти. Эти утечки можно обнаружить, при многократном выполнении функции:

>>> import freq.

>>> for i in xrange(1000000):

... dummy = freq.frequency("ABCDEF").

>>>

Если функция freq.frequency() имеет утечки памяти, выполняемый процесс очень быстро займет всю имеющуюся память.