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:

  1. Write the application entirely in language A.
  2. Write the application entirely in language B.
  3. 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:

#include “stdafx.h”

#include <iostream>

#include <Python.h>

int _tmain(int argc, _TCHAR* argv[])

{

printf(“Calling Python to find the sum of 2 and 2.\n”);

// Initialize the Python interpreter.

Py_Initialize();

// 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.

Py_Finalize();

// 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):

return 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.

Future Work

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.

7 thoughts to “Calling Python Code from C++

  • Avatar
    Raghav

    If the above code doesn’t work, try adding the following lines just below Py_Initialize();

    PyRun_SimpleString(“import sys”);
    PyRun_SimpleString(“sys.path.append(\”.\”)”);

    Reply
  • Avatar
    Jessica

    Hi, I have added the above PyRun_SimpleString() two lines. Still my pFunc is 0 after executing
    PyDict_GetItemString(pDict, “Solver”); Solver is the function name defined in my python codes.

    Could anyone give a hint what is being wrong? Thanks.

    Reply
    • Jonathan Kauffman
      Jonathan Kauffman

      Hi Jessica,

      What is the name of the .py file that contains the “Solver” function? Does it match the parameter passed to this method?:

      pName = PyString_FromString(“YourFileName”);

      Jonathan

      Reply
  • Avatar
    Miguel

    Hi, first of all thanks for this article, it has been very useful so far. However, I haven’t be able to make it work yet. I have the following code:

    Py_Initialize();// Initialize the Python interpreter.

    std::cout << "Python interpreter intialized" << std::endl;

    PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;// Create some Python objects that will later be assigned values.

    std::cout << "Python objects created" << std::endl;

    pName = PyUnicode_FromString("test");// Convert the file name to a Python string.

    if (pName == NULL) {
    std::cout << "ERROR: name pointer is null" << std::endl;
    }
    else {
    std::cout << "Name of the python module assigned" << std::endl;
    }

    pModule = PyImport_Import(pName);// Import the file as a Python module.

    if (pModule == NULL) {
    std::cout << "ERROR: module pointer is null" << std::endl;
    }
    else {
    std::cout << "Python module imported" << std::endl;
    }

    pDict = PyModule_GetDict(pModule);// Create a dictionary for the contents of the module.

    if (pDict == NULL) {
    std::cout << "ERROR: dictionary pointer is null" << std::endl;
    }
    else {
    std::cout << "Python dictionary of the module functions created" << std::endl;
    }

    //pFunc = PyDict_GetItemString(pDict, "add");// Get the add method from the dictionary.
    pFunc = PyUnicode_FromString("add");

    if (pFunc == NULL) {
    std::cout << "ERROR: function pointer is null" << std::endl;
    }
    else {
    std::cout << "Python function found" << std::endl;
    }

    pArgs = PyTuple_New(2);// Create a Python tuple to hold the arguments to the method.

    if (pArgs == NULL) {
    std::cout << "ERROR: Arguments pointer is null" << std::endl;
    }
    else {
    std::cout << "Python arguments tuple created" << std::endl;
    }

    pValue = PyLong_FromLong(2);// Convert 2 to a Python integer.

    if (pValue == NULL) {
    std::cout << "ERROR: Value pointer is null" << std::endl;
    }
    else {
    std::cout << "Python argument value assgined" << std::endl;
    }

    PyTuple_SetItem(pArgs, 0, pValue);// Set the Python int as the first and second arguments to the method.
    PyTuple_SetItem(pArgs, 1, pValue);

    std::cout << "Python arguments assgined to tuple" << std::endl;

    PyObject* pResult = PyObject_CallObject(pFunc, pArgs);// Call the function with the arguments.

    if (pResult == NULL) {
    std::cout << "ERROR: Result pointer is null" << std::endl;// Print a message if calling the method failed.
    }
    else {
    long result = PyLong_AsLong(pResult);// Convert the result to a long from a Python object.
    std::cout << "The result is " << result;// Print the result.
    }

    Py_Finalize();// Destroy the Python interpreter.

    But i get:

    Python interpreter intialized
    Python objects created
    Name of the python module assigned
    Python module imported
    Python dictionary of the module functions created
    Python function found
    Python arguments tuple created
    Python argument value assgined
    Python arguments assgined to tuple
    ERROR: Result pointer is null

    The python code is just test.py:

    def add(a, b):
    return a+b

    I am using visul studio if it is of any relevance.

    Thanks in advance for your time!

    Reply
    • Jonathan Kauffman
      Jonathan Kauffman

      Hi Miguel,

      The documentation for the PyObject_CallObject method indicates that the method both returns NULL and raises an exception when it fails. Can you provide the details of the exception that is raised as well?

      Jonathan

      Reply
  • Avatar
    sushant

    Python interpreter intialized
    Python objects created
    Name of the python module assigned
    ERROR: module pointer is null

    Reply
    • Jonathan Kauffman
      Jonathan Kauffman

      Hi Sushant,

      What is the name of the .py file with the method that you want to call? Does the name of the file match the argument passed to the following method?

      pName = PyUnicode_FromString(“test”);

      Jonathan

      Reply

Leave a comment

Your email address will not be published. Required fields are marked *

X