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.

22 thoughts to “Calling Python Code from C++

  • 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
  • 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

      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
  • 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

      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
  • sushant

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

    Reply
    • 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
  • Mohamed

    I receive Segmentation fault (core dumped) when i run the code.

    Reply
    • Jonathan Kauffman

      Hi Mohamed,

      Are there any differences between your code and the code in the post? Can you provide more details about your environment, such as the versions of Visual Studio and Python that you are using?

      Jonathan

      Reply
  • Patrick Siandji Djumedio

    hi I can not add my Python file to the Release directory of the Visual Studio solution.could you tell me how I should proceed in Visual Studio? then whithout the addition I receive an execution of the type: Exception raised to 0x00007FFF92660FD4 (python37 .dll) in python_to_cpp.exe: 0xC0000005: location of reading the access violation 0x00000000000000000008. occurred

    below my c ++ and python code

    ######### c code ++ ########################################################################

    #include
    #include

    int main(int argc, const wchar_t* argv[])
    {

    // 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 = PyUnicode_FromString(“C:/Users/siand/Downloads/test”);
    //pName = PyString_FromString(“C:/test.py”);

    // 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 = PyLong_FromLong(2);
    //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 = PyLong_AsLong(pResult);
    //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;
    }
    ### python code ki is stored in C: /Users/sam/Downloads/test.py on my computer ###

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

    if __name __ == “__ main__”:

    print ( hello )

    a = input (“a:”)
    b = entry (“b:”)
    print (add (int (a), int (b))

    Reply
    • Jonathan Kauffman

      Hi Patrick,

      Why are you not able to add the Python file to the Release directory? Does the directory not exist? Or is there some problem with adding the file to it?

      Jonathan

      Reply
  • Patrick Siandji Djumedio

    Thanks for your quick response Jonathan.
    I don’t know where to put the Python code in the visual studio.
    ist it unter:
    >project_name
    >property
    > C/C++
    > General ->Additionale include directry

    the path to my Python code is C:\Users\sam\Downloads\test.py

    thanks

    Reply
    • Jonathan Kauffman

      If you navigate to the project using Windows Explorer you should be able to find a Release directory. I think that there might be multiple Release directories, so you’ll have to do some experimentation to figure out which one works.

      Reply
  • Patrick Siandji Djumedio

    I still get this execption: Exception thrown at 0x00007FFF930B0FD4 (python37.dll) in python_to_cpp.exe: 0xC0000005: Access violation reading location 0x0000000000000008.

    Reply
    • Jonathan Kauffman

      Did you update the following line after moving the Python file to the Release directory?

      pName = PyUnicode_FromString(“C:/Users/siand/Downloads/test”);

      If not, and your Python file is named test.py, you should change that line to:

      pName = PyUnicode_FromString(“test”);

      Reply
  • Patrick Siandji Djumedio

    yes I did it.but i got it as output:
    ######### Output ###############

    Name of the python module assigned
    Python module imported
    Python dictionary of the module functions created
    Python function found
    Python arguments tuple created
    ERROR: Value pointer is null
    Python argument value assgined
    Calling the add method failed. 🙁
    SystemError: G:\ade\build\sb_0-36732646-1573733864.51\Python-3.7.4-export-15549617\Python-3.7.4\Objects\longobject.c:415: bad argument to internal function
    The result is -1.

    #### my new code c++ is:
    #include
    #include
    //#include
    //#include

    int main(int argc, const wchar_t* argv[])
    {
    //char filename[] = “D:/Master-Computer-engenniering/Semester 2/Lego_Projekt_entwicklung_Thomas/train_lego_with_Mobilnet/lego_Test.py”;
    // char filename[] = “C:/test.py”;
    //FILE* fp;
    //Py_SetProgramName(argv[0]);

    // 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 = PyUnicode_FromString(“test”);
    //pName = PyString_FromString(“C:/test.py”);
    if (pName == NULL)
    {
    std::cout << "ERROR: name pointer is null" << std::endl;
    }
    else {
    std::cout << "Name of the python module assigned" << std::endl;
    }
    // Import the file as a Python module.

    pModule = PyImport_Import(pName);
    if (pModule == NULL) {
    std::cout << "ERROR: module pointer is null" << std::endl;
    }
    else {
    std::cout << "Python module imported" << std::endl;
    // Create a dictionary for the contents of the module.
    }
    pDict = PyModule_GetDict(pModule);
    if (pDict == NULL) {
    std::cout << "ERROR: dictionary pointer is null" << std::endl;
    }
    else {
    std::cout << "Python dictionary of the module functions created" << std::endl;
    }
    // Get the add method from the dictionary.

    //pFunc = PyDict_GetItemString(pDict, "add");
    pFunc = PyUnicode_FromString("add");
    if (pFunc == NULL) {
    std::cout << "ERROR: function pointer is null" << std::endl;
    }
    else {
    std::cout << "Python function found" << std::endl;
    }
    // Create a Python tuple to hold the arguments to the method.

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

    // Convert 2 to a Python integer.
    pValue = PyLong_FromLong(2);
    if (pValue == NULL) {
    std::cout << "ERREUR: le pointeur de valeur est nul" << std::endl;
    }
    else {
    std::cout << "ERROR: Value pointer is null" << std::endl;
    }
    //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);
    std::cout << "Python argument value assgined" << std::endl;
    // 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 = PyLong_AsLong(pResult);
    //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;
    }

    ### Python code #########
    def add(a,b):
    return a+b

    if __name__=="__main__":

    print("hello ")
    a=2
    b=5
    b=add(a,b)
    print(b)

    Reply
    • Jonathan Kauffman

      I see that you’re using PyLong_AsLong instead of PyInt_AsLong — maybe try using “2L” instead of “2” to force the int to be a long? I don’t have this project set up anymore, so I unfortunately can’t try things out myself.

      Reply
  • Pingback: Cannot import Python.h – Windows Questions

  • Pingback: I can’t include python.h in omnet – Windows Questions

  • Pingback: I can’t include python.h in omnet – Ask python questions

  • Nicola

    Hey thx for the great work. I run in a Problem with my code. Hope you can help
    Code i use
    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
    TypeError : `str` object is not callable
    The python code is just test.py:

    def add(a, b):
    return a+b
    I use a viruelle Linux machine and QT.

    Reply
    • Jonathan Kauffman

      Hi Nicola,

      I think that this line might be the problem:

      pFunc = PyUnicode_FromString(“add”);

      Instead of returning a function reference, this line will return a Unicode object. I see that you have the line that was in the original post commented out:

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

      What happens if you use the commented-out line instead?

      Jonathan

      Reply

Leave a comment

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

X