Calling Python code from a C++ application


Calling Python from C++

Have you ever been writing C++ and you find yourself writing non-performance-critical code that would be absolutely trivial in Python? Or perhaps there is some complex problem that has an optimized solution in a python package, and if you could just call it from your C++ code life would be so much better. It turns out that this is fairly easy to do. I’ve talked about using Cython to wrap C/C++ for python, and as it happens, Cython can this job in reverse as well. To demonstrate this, I’ll call into the art package from a simple C++ program. First, we need the art package installed:

pip install art

Now lets write a Cython file that exposes a function that accepts a std::string and calls the text2art function in the art package and returns the result.

# art_wrapper.pyx

from libcpp.string cimport string
from art import text2art as _text2art

cdef public string text2art(string text):
    return _text2art(text)
If you don’t have Cython installed, you will also need to:

pip install cython
Because we used the public keyword in our cdef function, when we call:

cython -2 art_wrapper.pyx

Two files are generated: art_wrapper.c and art_wrapper.h. We include this generated header file in our C++ program:

// main.cpp

#include  <iostream>
#include  "Python.h"
#include  "art_wrapper.h"

int  main(int argc, char  *argv[])
    std::cout << text2art("Python in C++!") << std::endl;
    return 0;

Now we are ready to build!

g++ art_wrapper.c main.cpp -o main $(python-config --libs)  $(python-config --includes)  $(python-config --cflags)

Lets run it!

$ ./main
               _    _                     _           ____                _ 
 _ __   _   _ | |_ | |__    ___   _ __   (_) _ __    / ___|   _      _   | |
| '_ \ | | | || __|| '_ \  / _ \ | '_ \  | || '_ \  | |     _| |_  _| |_ | |
| |_) || |_| || |_ | | | || (_) || | | | | || | | | | |___ |_   _||_   _||_|
| .__/  \__, | \__||_| |_| \___/ |_| |_| |_||_| |_|  \____|  |_|    |_|  (_)
|_|     |___/                                                               

A few notes:
  • I hope this is obvious, but including Python.h and running Py_Initialize embeds the python interpreter in your C++ application. Python is pretty light-weight, so this is generally not a problem.
  • This executable depends on python being installed on the system. In particular, the python shared libraries will need to be installed in a location where the loader can map them into the process at load-time. This is not a problem if python is installed on the target system in the usual way.
  • The call to initart_wrapper is Python2 specific. If you are using Python3, you would do: PyImport_AppendInittab("art_wrapper", PyInit_art_wrapper); prior to the Py_Initialize call. (the art_wrapper part of the function name is the cython module name, substitute your module name)
  • In the Cython code, all the public function should return a C++ type and all the parameters should be C++ types. If you do not annotate the types, the type will default to PyObject* which introduces unnecessary complexity in your C++ code, especially if you are not already comfortable with the Python C-API.
  • The python-config program is awesome. Use it to generate the libs/includes/compiler flags.

2 thoughts on “Calling Python code from a C++ application

  1. You need much more to make this example work in python3 than what you put in the third note.
    1) you need a call both before and after the Py_Initialize call, otherwise you get a segmentation fault:
    PyImport_AppendInittab(“art_wrapper”, PyInit_art_wrapper);
    2) you also need to mess around with the unicode string types in your pyx file:
    cdef public string text2art(string text):
    utext = text.decode(‘UTF-8’)
    cdef string result = _text2art(utext).encode(‘UTF-8’)
    return result

Leave a Reply

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