In one of our projects the requirement to run small user-defined Python scripts inside a C++ application arose. Thanks to Python’s C-API, nicknamed CPython, embedding (really) simple scripts is pretty straightforward:
Py_Initialize(); const char* pythonScript = "print 'Hello, world!'\n"; int result = PyRun_SimpleString(pythonScript); Py_Finalize();
Yet, this approach does neither allow running extensive scripts, nor does it provide a way to exchange data between the application and the script. The result of this operation merely indicates whether the script was executed properly by returning 0, or -1 otherwise, e.g. if an exception was raised. To overcome these limitations, CPython offers another, more versatile way to execute scripts:
PyObject* PyRun_String(const char* pythonScript, int startToken, PyObject* globalDictionary, PyObject* localDictionary)
Besides the actual script, this function requires a start token, which should be set to Py_file_input for larger scripts, and two dictionaries containing the exchanged data:
PyObject* main = PyImport_AddModule("__main__"); PyObject* globalDictionary = PyModule_GetDict(main); PyObject* localDictionary = PyDict_New(); PyObject* result = PyRun_String(pythonScript, Py_file_input, globalDictionary, localDictionary);
Communication between the application and the script is done by inserting entries to one of the dictionaries prior to running the script:
PyObject* value = PyString_FromString("some value"); PyDict_SetItemString(localDict, "someKey", value);
Doing so makes the variable “someKey” and its value available inside the Python script. Accessing the produced data after running the Python script is just as easy:
char* result = String_AsString(PyDict_GetItemString(localDict, "someKey"));
If a variable is created inside the Python script, this variable also becomes accessible from the application through PyDict_GetItemString (or PyDict_GetItem), even if it was not entered into the dictionary beforehand.
The following example shows the complete process of defining variables as dictionary entries, running a small script and retrieving the produced result in the C++ application:
Py_Initialize(); //create the dictionaries as shown above const char* pythonScript = "result = multiplicand * multiplier\n"; PyDict_SetItemString(localDictionary, "multiplicand", PyInt_FromLong(2)); PyDict_SetItemString(localDictionary, "multiplier", PyInt_FromLong(5)); PyRun_String(pythonScript, Py_file_input, globalDictionary, localDictionary); long result = PyInt_AsLong(PyDict_GetItemString(localDictionary, "result")); cout << result << endl; Py_Finalize();
2 thoughts on “Embedding Python into C++”