KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Роман Сузи - Язык программирования Python

Роман Сузи - Язык программирования Python

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Роман Сузи, "Язык программирования Python" бесплатно, без регистрации.
Перейти на страницу:

Интерпретатор Python может быть встроен в программу на C с использованием C API. Это лучше всего демонстрирует уже работающий пример:

/* File : demo.c */

/* Пример встраивания интерпретатора Python в другую программу */

#include "Python.h"


main(int argc, char **argv) {

 /* Передает argv[0] интерпретатору Python */

 Py_SetProgramName(argv[0]);


 /* Инициализация интерпретатора */

 Py_Initialize();


 /* ... */


 /* Выполнение операторов Python (как бы модуль __main__) */

 PyRun_SimpleString("import timen");

 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++. Последнее очень важно, если необходимо создать интерфейс к библиотеке шаблонов.

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

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

Язык программирования Python является сценарным языком, а значит его основное назначение — интеграция в единую систему разнородных программных компонентов. Выше рассматривалась (низкоуровневая) интеграция с C/C++-приложениями. Нужно заметить, что в большинстве случаев достаточно интеграции с использованием протокола. Например, интегрируемые приложения могут общаться через XML–RPC, SOAP, CORBA, COM, .NET и т.п. В случаях, когда приложения имеют интерфейс командной строки, их можно вызывать из Python и управлять стандартным вводом–выводом, переменными окружения. Однако есть и более интересные варианты интеграции.

Современное состояние дел по излагаемому вопросу можно узнать по адресу: http://www.python.org/moin/IntegratingPythonWithOtherLanguages

Java

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

• Jython–код динамически компилирует байт-коды Java, хотя возможна и статическая компиляция, что позволяет писать апплеты, сервлеты и т.п.;

• Поддерживает объектно–ориентированную модель Java, в том числе, возможность наследовать от абстрактных Java–классов;

• Jython является реализацией Python — языка с практичным синтаксисом, обладающего большой выразительностью, что позволяет сократить сроки разработки приложений в разы.

Правда, имеются и некоторые ограничения по сравнению с «обычным» Python. Например, Java не поддерживает множественного наследования, поэтому в некоторых версиях Jython нельзя наследовать классы от нескольких Java–классов (в тоже время, множественное наследование поддерживается для Python–классов).

Следующий пример (файл lines.py) показывает полную интеграцию Java–классов с интерпретатором Python:

# Импортируются модули из Java

from java.lang import System

from java.awt import *

# А это модуль из Jython

import random


# Класс для рисования линий на рисунке

class Lines(Canvas):

 # Реализация метода paint()

 def paint(self, g):

  X, Y = self.getSize().width, self.getSize().height

  label.setText("%s x %s" % (X, Y))

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*