При разработке прикладных программ иногда возникает необходимость предоставить пользователю какую-то достаточно гибкую, но простую систему для управления программой.
Есть множество вариантов реализации таких систем, но одним из наиболее простых является встраивание в приложение интерпретатора скриптовых языков.
Реализацией этого варианта мы сегодня и займемся. В качестве скриптового языка был выбран Python из-за достаточно большого спектра применения.
Он кроссплатформенный, существуют официальные версии для Windows, Linux и MacOS. В конце концов, о мощи и потенциале этого языка может говорить хотя бы тот факт, что он используется в небезызвестной корпорации Google как основной язык программирования.
Качаем с www.python.org последний релиз интерпретатора языка и устанавливаем его куда-нибудь. Проверяем наличие следующих файлов:
{путь установки}\Python\include\Python.h
{путь установки}Python\libs\python31.lib (или libpython31.a, если вы используете gcc)
Если этих файлов нет, нужно скачать с официального сайта исходники интерпретатора и распаковать их куда-нибудь. Создайте проект в любой IDE (например, MS VS 2005) и пропишите в настройках подключаемых модулей пути к папкам с этими файлами.
Теперь ее обсудим.
Первым делом подключается Python.h для получения доступа к Python API.
Перед работой с интерпретатором необходимо обязательно вызывать Py_Initialize, после ее окончания Py_Finalize. Один из способов вызвать на выполнение нужный скрипт – это функция PyRun_SimpleString.
Она принимает в качестве параметра строку со скриптом и выполняет. В приведенном примере функция выведет на экран текущее время. Однако в большинстве случаев этого недостаточно.
Предположим, что нам нужна программа для построения графиков мат. функций. Если это простая функция вроде у = x + 1 ― cos(x), то проблем с вводом не возникнет, достаточно написать простой парсер выражений на основе обратной польской записи. Но функций могут быть и более сложные, например:
Тут уже с организацией пользовательского ввода имеются проблемы. Но можно дать возможность пользователю написать данную функцию на скриптовом языке. Например, на том же Python’е. Этим мы и займемся. Для начала, необходимо сделать следующее:
И наша функция y(x) на Python-е записывается так:
Функция, вызывающая скрипт с функцией y(x) из модуля:
Обсудим использованные функции, не особо вдаваясь в подробности, т. к. цель данной статьи состоит в рассказе об основных моментах встраивания Python’а в приложения. Для получения более подробных сведений можно почитать документацию на официальном сайте.
Функции вида Py*_From* позволяют преобразовывать встроенные типы С/C++ во внутренние типы Python’а. Т. е., например, PyUnicode_FromString преобразует свой строковый параметр во внутреннее юникодовое представление Python’а для того, чтобы интерпретатор языка смог потом с ним (с параметром) работать. Функции вида Py*_As* имеют обратное действие (т.е. преобразовывают типы из внутреннего представления интерпретатора во встроенные типы C/C++).
PyImport_Import позволяет получить доступ к функциям модуля, имя которого указывается в качестве параметра. Тип параметра, разумеется, нужно предварительно преобразовать во внутреннее представление.
Py_DECREF ― макрос, высвобождающий память, занятую используемыми интерпретатором данными. Этот макрос отличается от Py_XDECREF тем, что последний может принимать нулевые значения в качестве параметра. Например, следующий фрагмент преобразует строку «mod» во внутренний тип Python’а и загружает нужный модуль.
После этого объект, содержащий строку, более не нужен, поэтому память очищается при помощи Py_DECREF.
PyObject_GetAttrString возвращает указатель на функцию из модуля, указанного в качестве первого параметра с именем, указанным в качестве второго.
Для передачи параметров функциям используются так называемые «tuples». Далее для простоты будем называть их кортежами. Кортежи – наборы определенного количества значений разных типов. Для создания нового кортежа используется функция PyTuple_New с указанием нужного числа передаваемых аргументов. Потом кортеж заполняется значениями при помощи PyTuple_SetItem, первый аргумент которой – кортеж, второй – порядковый номер аргумента, а третий – его значение. После этого можно вызвать функцию PyObject_CallObject, передав ей функцию и кортеж аргументов.
Теперь организация ввода пользователем исходных данных не составляет проблемы.
Тут все возможности Python-a раскрыты небыли, но данная статья послужит стартом для изучения, и в этом вам поможет документация на www.python.org
Есть множество вариантов реализации таких систем, но одним из наиболее простых является встраивание в приложение интерпретатора скриптовых языков.
Реализацией этого варианта мы сегодня и займемся. В качестве скриптового языка был выбран 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), то проблем с вводом не возникнет, достаточно написать простой парсер выражений на основе обратной польской записи. Но функций могут быть и более сложные, например:
Тут уже с организацией пользовательского ввода имеются проблемы. Но можно дать возможность пользователю написать данную функцию на скриптовом языке. Например, на том же 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