When developing an application in programming language A you may discover that certain parts of the program are easier to code using a different language B. At this point you have one of three choices:
- Write the application entirely in language A.
- Write the application entirely in language B.
- Write most of the application using language A and call language B from A when appropriate.
The downsides of the first two approaches are that you sacrifice the benefits of writing parts of the application in one language for the sake of using a uniform language. By using the third approach you overcome these downsides at the cost of the context switching required to start executing code in a different language. However, depending on the frequency with which the program will execute code written in language B, this trade-off may be acceptable.
In the Active Authentication project we are writing C++ code that leverages the Detours library to collect system call traces. However, there are several implementations of algorithms used to process these system call traces that are available in Python. We could translate these algorithms to C++, but because this is a research project we decided to refrain from doing so until we had evidence that calling the Python code from C++ incurs an unacceptable time overhead. In this post I will, through the use of a simple example, describe how to call a Python function from C++ and retrieve its return value. I will assume that you already have Microsoft Visual Studio and Python installed on your computer. The following example was tested with Visual Studio 2010 Professional and Python 2.7.3.
Creating the Visual Studio Project
Open Visual Studio and create a new C++ “Win32 Console Application” project. Before you can call Python code you need to tell Visual Studio how to find Python. Before doing this change the build mode from “Debug” to “Release”. If you attempt to build a Visual Studio project that calls Python code in Debug mode the build will fail because, in debugging mode, Visual Studio will look for a library file that does not exist. The reason why this file did not exist on my machine is because the Windows Python installer did not install a version of Python compiled in Debug mode. It is possible to get a version of Python built in Debug mode, but you will have to download the Python source code and build it manually. For the purposes of this blog post we will ignore this and just change to Release mode.
Next you need to add the locations of the Python header and library files to the project properties. My Python installation directory was “C:\Python27”, so I added “C:\Python27\include” to the list of include directories and “C:\Python27\libs” to the list of library directories. After making these changes to the properties you should be able to add the line “#include <Python.h>” to the C++ source file and build the project without error.
You can now replace the contents of your C++ source file with the following source code example:
int _tmain(int argc, _TCHAR* argv)
printf(“Calling Python to find the sum of 2 and 2.\n”);
// Initialize the Python interpreter.
// Create some Python objects that will later be assigned values.
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;
// Convert the file name to a Python string.
pName = PyString_FromString(“Sample”);
// Import the file as a Python module.
pModule = PyImport_Import(pName);
// Create a dictionary for the contents of the module.
pDict = PyModule_GetDict(pModule);
// Get the add method from the dictionary.
pFunc = PyDict_GetItemString(pDict, “add”);
// Create a Python tuple to hold the arguments to the method.
pArgs = PyTuple_New(2);
// Convert 2 to a Python integer.
pValue = PyInt_FromLong(2);
// Set the Python int as the first and second arguments to the method.
PyTuple_SetItem(pArgs, 0, pValue);
PyTuple_SetItem(pArgs, 1, pValue);
// Call the function with the arguments.
PyObject* pResult = PyObject_CallObject(pFunc, pArgs);
// Print a message if calling the method failed.
if(pResult == NULL)
printf(“Calling the add method failed.\n”);
// Convert the result to a long from a Python object.
long result = PyInt_AsLong(pResult);
// Destroy the Python interpreter.
// Print the result.
printf(“The result is %d.\n”, result); std::cin.ignore(); return 0; }
Since the code comments describe the purpose of almost every statement I will simply describe what the code does at a high level. This program calls a Python function that returns the sum of two numbers. First the program creates a Python interpreter so that it can execute Python code. The program then retrieves the method from the Python source file and prepares the arguments that will be sent to the method. The C++ code then calls the function, retrieves the result, and destroys the Python interpreter. Finally, the program prints the result of adding 2 and 2. Now that the C++ code is ready you need to write the Python code that will be called.
Creating the Python File
Next you should add the Python function “add” that will be called from C++ to a file named “Sample.py”. The code for this function is:
# Returns the sum of two numbers.
def add(a, b):
Add this file to the Release directory of the Visual Studio solution. In general it should be in the same directory as the executable that is calling the Python code.
After creating the Python file you should be able to run the Visual Studio project and see the following output:
Calling Python to find the sum of 2 and 2. The result is 4.
In the Active Authentication project we created Python objects that we accessed and modified throughout the execution of a C++ program. In a future post I may describe how to manage Python objects from C++ and serialize them so that they can be accessed during subsequent program executions. Another possible topic for a future post is a performance comparison of two versions of some simple (yet realistic) C++ program – one that executes a subroutine written in C++ and another that calls Python code to perform the same task.