Pull to refresh

Используем Python в своей программе

Reading time 4 min
Views 36K
При разработке прикладных программ иногда возникает необходимость предоставить пользователю какую-то достаточно гибкую, но простую систему для управления программой.

Есть множество вариантов реализации таких систем, но одним из наиболее простых является встраивание в приложение интерпретатора скриптовых языков.

Реализацией этого варианта мы сегодня и займемся. В качестве скриптового языка был выбран Python из-за достаточно большого спектра применения.

Он кроссплатформенный, существуют официальные версии для Windows, Linux и MacOS. В конце концов, о мощи и потенциале этого языка может говорить хотя бы тот факт, что он используется в небезызвестной корпорации Google как основной язык программирования.

На старт

Качаем с www.python.org последний релиз интерпретатора языка и устанавливаем его куда-нибудь. Проверяем наличие следующих файлов:

{путь установки}\Python\include\Python.h

{путь установки}Python\libs\python31.lib (или libpython31.a, если вы используете gcc)

Если этих файлов нет, нужно скачать с официального сайта исходники интерпретатора и распаковать их куда-нибудь. Создайте проект в любой IDE (например, MS VS 2005) и пропишите в настройках подключаемых модулей пути к папкам с этими файлами.

Простенькая программка

#include
int main(int argc, char *argv[])
{
Py_Initialize(); // инициализация интерпретатора
PyRun_SimpleString("from time import time,ctime\n"
"print('Today is', ctime(time()))\n");
// выполняется нужный скрипт
Py_Finalize(); // очищение памяти, отданной интерпретатору
return 0;
}


Теперь ее обсудим.

Первым делом подключается Python.h для получения доступа к Python API.

Перед работой с интерпретатором необходимо обязательно вызывать Py_Initialize, после ее окончания Py_Finalize. Один из способов вызвать на выполнение нужный скрипт – это функция PyRun_SimpleString.
Она принимает в качестве параметра строку со скриптом и выполняет. В приведенном примере функция выведет на экран текущее время. Однако в большинстве случаев этого недостаточно.

Получение результата выполнения функции

Предположим, что нам нужна программа для построения графиков мат. функций. Если это простая функция вроде у = x + 1 ― cos(x), то проблем с вводом не возникнет, достаточно написать простой парсер выражений на основе обратной польской записи. Но функций могут быть и более сложные, например:

image

Тут уже с организацией пользовательского ввода имеются проблемы. Но можно дать возможность пользователю написать данную функцию на скриптовом языке. Например, на том же Python’е. Этим мы и займемся. Для начала, необходимо сделать следующее:
  • Передаем параметр функции, написанной на Python-е
  • Выполняем её
  • Получаем результат

И наша функция y(x) на Python-е записывается так:

def func(x):
if x > 3:
return x + 1
elif 1 < x <= 3:
return 0
else:
return x ** x


Функция, вызывающая скрипт с функцией y(x) из модуля:

double compute(double x)
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue;
double result = 0.0;
Py_Initialize();
pName = PyUnicode_FromString("mod");
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL)
{
pFunc = PyObject_GetAttrString(pModule, "func");
if (pFunc && PyCallable_Check(pFunc))
{
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, PyFloat_FromDouble(x));
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL)
{
result = PyFloat_AsDouble(pValue);
Py_DECREF(pValue);
}
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
Py_Finalize();
return result;
}


Обсудим использованные функции, не особо вдаваясь в подробности, т. к. цель данной статьи состоит в рассказе об основных моментах встраивания Python’а в приложения. Для получения более подробных сведений можно почитать документацию на официальном сайте.

Функции вида Py*_From* позволяют преобразовывать встроенные типы С/C++ во внутренние типы Python’а. Т. е., например, PyUnicode_FromString преобразует свой строковый параметр во внутреннее юникодовое представление Python’а для того, чтобы интерпретатор языка смог потом с ним (с параметром) работать. Функции вида Py*_As* имеют обратное действие (т.е. преобразовывают типы из внутреннего представления интерпретатора во встроенные типы C/C++).

PyImport_Import позволяет получить доступ к функциям модуля, имя которого указывается в качестве параметра. Тип параметра, разумеется, нужно предварительно преобразовать во внутреннее представление.

Py_DECREF ― макрос, высвобождающий память, занятую используемыми интерпретатором данными. Этот макрос отличается от Py_XDECREF тем, что последний может принимать нулевые значения в качестве параметра. Например, следующий фрагмент преобразует строку «mod» во внутренний тип Python’а и загружает нужный модуль.

pName = PyUnicode_FromString("mod");
pModule = PyImport_Import(pName);
Py_DECREF(pName);


После этого объект, содержащий строку, более не нужен, поэтому память очищается при помощи Py_DECREF.

PyObject_GetAttrString возвращает указатель на функцию из модуля, указанного в качестве первого параметра с именем, указанным в качестве второго.

Для передачи параметров функциям используются так называемые «tuples». Далее для простоты будем называть их кортежами. Кортежи – наборы определенного количества значений разных типов. Для создания нового кортежа используется функция PyTuple_New с указанием нужного числа передаваемых аргументов. Потом кортеж заполняется значениями при помощи PyTuple_SetItem, первый аргумент которой – кортеж, второй – порядковый номер аргумента, а третий – его значение. После этого можно вызвать функцию PyObject_CallObject, передав ей функцию и кортеж аргументов.
Теперь организация ввода пользователем исходных данных не составляет проблемы.

Заключение

Тут все возможности Python-a раскрыты небыли, но данная статья послужит стартом для изучения, и в этом вам поможет документация на www.python.org
Tags:
Hubs:
+30
Comments 38
Comments Comments 38

Articles