Опубликован: 22.12.2005 | Доступ: свободный | Студентов: 16816 / 518 | Оценка: 4.18 / 3.71 | Длительность: 16:16:00
ISBN: 978-5-9556-0109-0
Лекция 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 >
Андрей Егоров
Андрей Егоров

def bin(n):

"""Цифры двоичного представления натурального числа """

if n == 0:

   return []

n, d = divmod(n, 2)

return bin(n) + [d]

print bin(69)

Что значит здесь return[] ? Возвращает список? Непонятно какой список? Откуда он? 

 

 

Асмик Гаряка
Асмик Гаряка

Почему при вычислении рейтинга не учитывается уровень, как описано? Для всех курсов У=1, хотя для Специалист должно быть 2.

Дмитрий Кузьмин
Дмитрий Кузьмин
Россия
Владимир Крюков
Владимир Крюков
Казахстан