When developing applications, it is sometimes necessary to provide the user with some kind of quite flexible but simple system for managing the program.
There are many options for the implementation of such systems, but one of the most simple is the embedding of scripting languages into the application interpreter.
The implementation of this option today we will do. Python was chosen as the scripting language due to a rather large range of applications.
')
It is cross-platform, there are official versions for Windows, Linux and MacOS. In the end, at least the fact that it is used in the infamous Google corporation as the main programming language can speak about the power and potential of this language.
On your marks
We download the latest release of the language interpreter from
www.python.org and install it somewhere. Check for the following files:
{install path} \ Python \ include \ Python.h
{install path} Python \ libs \ python31.lib (or libpython31.a if you are using gcc)
If these files are not available, you need to download the interpreter sources from the official site and unpack them somewhere. Create a project in any IDE (for example, MS VS 2005) and write the paths to the folders with these files in the settings of the plug-ins.
Simple program
#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;
}
Now we will discuss it.
First of all, Python.h connects to get access to the Python API.
Before working with the interpreter, it is necessary to call Py_Initialize, after its termination Py_Finalize. One of the ways to invoke the necessary script is the PyRun_SimpleString function.
It takes as a parameter a string with a script and executes. In the example above, the function will display the current time. However, in most cases this is not enough.
Getting the result of the function
Suppose that we need a program for plotting mat. functions. If this is a simple function like y = x + 1 - cos (x), then there will be no problems with the input, it is enough to write a simple expression parser based on the reverse Polish notation. But functions can be more complex, for example:
There are already problems with the organization of user input. But you can enable the user to write this function in a scripting language. For example, on the same Python. This is what we will do. First, do the following:
- Pass a parameter to a function written in Python
- Do it
- We get the result
And our function y (x) in Python is written like this:
def func(x):
if x > 3:
return x + 1
elif 1 < x <= 3:
return 0
else:
return x ** x
The function that calls the script with the function y (x) from the module:
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;
}
We will discuss the functions used, without really going into details, because the purpose of this article is to describe the main points of embedding Python in applications. For more information, you can read the documentation on the official site.
Functions like Py * _From * allow you to convert built-in C / C ++ types to internal Python types. That is, for example, PyUnicode_FromString converts its string parameter into the internal Unicode representation of Python so that the language interpreter can then work with it (with the parameter). Functions of the form Py * _As * have the opposite effect (that is, they convert types from the internal representation of the interpreter to built-in C / C ++ types).
PyImport_Import allows you to access the functions of a module whose name is specified as a parameter. The type of the parameter, of course, must first be converted into an internal representation.
Py_DECREF is a macro that frees the memory occupied by the data used by the interpreter. This macro differs from Py_XDECREF in that it can take null values as a parameter. For example, the following fragment converts the string “mod” into the internal type of Python and loads the required module.
pName = PyUnicode_FromString("mod");
pModule = PyImport_Import(pName);
Py_DECREF(pName);
After this, the object containing the string is no longer needed, so the memory is cleared with Py_DECREF.
PyObject_GetAttrString returns a pointer to a function from the module specified as the first parameter with the name specified as the second.
To transfer parameters to functions, so-called “tuples” are used. Further, for simplicity, we will call them tuples. Tuples are sets of a certain number of values of different types. To create a new tuple, use the PyTuple_New function with the required number of passed arguments. Then the tuple is filled with values using PyTuple_SetItem, the first argument of which is a tuple, the second is the ordinal number of the argument, and the third is its value. After that, you can call the PyObject_CallObject function, passing it a function and a tuple of arguments.
Now the organization of the user input of the source data is not a problem.
Conclusion
All the features of Python are not disclosed here, but this article will be a start for studying, and the documentation on
www.python.org will help you with
this.