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

Доступные из языка Python модули расширяются за счет модулей расширения (extension modules). Модули расширения можно писать на языке C или C++ и вызывать из программ на Python. Немного о реализации Python, называемой CPython.

Сама необходимость использования языка C может возникнуть, если реализуемый алгоритм, будучи запрограммирован на Python, работает медленно. Модули расширения позволяют объединить эффективность порождаемого компилятором C/C++ кода c удобством и гибкостью интерпретатора Python. Необходимые сведения для создания модулей расширения для Python даны в исчерпывающем объеме в стандартной документации, а именно в документе «Python/C API Reference Manual» (справочное руководство по «Python/C API»). Здесь будут рассмотрены лишь основные принципы построения модуля расширения, без детальных подробностей об API. Стоит заметить, что возможности Python равно доступны и в C++, просто они выражены в C-декларациях, которые можно использовать в C++.

Все необходимые для модуля расширения определения находятся в заголовочном файле Python.h, который должен находится где-то на пути заголовочных файлов компилятора C/C++. Следует пользоваться теми же версиями библиотек, с которыми был откомпилирован Python. Желательно, и той же маркой компилятора C/C++.

Связь с интерпретатором Python из кода на C осуществляется путем вызова функций, определенных в интерпретаторе Python. Все функции начинаются на Py или _Py, потому во избежание конфликтов в модулях расширения не следует определять функций с подобными именами.

Через C API доступны все встроенные возможности языка Python.
Если необходимость встроить Python в программу возникает нечасто, то его расширение путем написания модулей на C/C++ — довольно распространенная практика. Изначально Python был нацелен на возможность расширения, поэтому в настоящий момент очень многие C/C++-библиотеки имеют привязки к Python.

Привязка к Python, хотя и может быть несколько автоматизирована, все же это процесс творческий. Дело в том, что если предполагается интенсивно использовать библиотеку в Python, ее привязку желательно сделать как можно более тщательно. Возможно, в ходе привязки будет сделана объектно-ориентированная надстройка или другие архитектурные изменения, которые позволят упростить использование библиотеки.
[code lang=»Python»]
// заголовочные файлы
#include "Python.h"
[/code]

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

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

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

Следующий пример (файл lines.py) показывает полную интеграцию Java-классов с интерпретатором Python:
[code lang=»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))
for i in range(100):
x1, y1 = random.randint(1, X), random.randint(1, Y)
x2, y2 = random.randint(1, X), random.randint(1, Y)
g.drawLine(x1, y1, x2, y2)

# Метки, кнопки и т.п.
panel = Panel(layout=BorderLayout())
label = Label("Size", Label.RIGHT)
panel.add(label, "North")
button = Button("QUIT", actionPerformed=lambda e: System.exit(0))
panel.add(button, "South")
lines = Lines()
panel.add(lines, ‘Center’)

# Запуск панели в окне
import pawt
pawt.test(panel, size=(240, 240))
[/code]
Программы на Jython можно компилировать в Java и собирать в jar-архивы. Для создания jar-архива на основе модуля (или пакета) можно применить команду jythonc, которая входит в комплект Jython. Из командной строки это можно сделать примерно так:
[code lang=»Python»]
jythonс -d -c -j lns.jar lines.py
[/code]
Для запуска приложения достаточно запустить lines из командной строки:
[code lang=»Python»]
java -classpath "$CLASSPATH" lines
[/code]
В переменной $CLASSPATH должны быть пути к архивам lns.jar и jython.jar.

Для написания модулей расширения можно использовать специальный язык — Pyrex — который совмещает синтаксис Python и типы данных C. Компилятор Pyrex написан на Python и превращает исходный файл (например, primes.pyx) в файл на C — готовый для компиляции модуль расширения. Но предпочтительней использовать Cython.
Для иллюстрации приведем пример файла из документации к Pyrex (для вычисления простых чисел):
[code lang=»Python»]
#
# Calculate prime numbers
#

def primes(int kmax):
cdef int n, k, i
cdef int p[1000]
result = []
if kmax > 1000:
kmax = 1000
k = 0
n = 2
while k < kmax:
i = 0
while i < k and n % p[i] <> 0:
i = i + 1
if i == k:
p[k] = n
k = k + 1
result.append(n)
n = n + 1
return result
[/code]
Разумеется, в Pyrex можно использовать C-библиотеки, именно поэтому он, как и SWIG, может служить для построения оберток C-библиотек для Python.

Следует отметить, что для простых операций Pyrex применяет C, а для обращения к объектам Python — вызовы Python/C API. Таким образом, объединяется выразительность Python и эффективность C. Конечно, некоторые вещи в Pyrex не доступны, например, генераторы, включения списков и Unicode, однако, цель Pyrex — создание быстродействующих модулей расширения, и для этого он превосходно подходит. Ознакомится с Pyrex можно по документации.