Опубликован: 22.12.2005 | Уровень: для всех | Доступ: платный
Лекция 13:

Интеграция Python с другими языками программирования

< Лекция 12 || Лекция 13: 12345 || Лекция 14 >

Использование 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() имеет утечки памяти, выполняемый процесс очень быстро займет всю имеющуюся память.

< Лекция 12 || Лекция 13: 12345 || Лекция 14 >
Сергей Крупко
Сергей Крупко

Добрый день.

Я сейчас прохожу курс  повышения квалификации  - "Профессиональное веб-программирование". Мне нужно получить диплом по этому курсу. Я так полагаю нужно его оплатить чтобы получить диплом о повышении квалификации. Как мне оплатить этот курс?

 

Павел Ялганов
Павел Ялганов

Скажите экзамен тоже будет ввиде теста? или там будет какое то практическое интересное задание?

Мария Кравцова
Мария Кравцова
Россия, Сочи, РГПУ им. А.И.Герцена, 1997
Екатерина Архангельская
Екатерина Архангельская
Россия, СПбГУАП