Functions

The simplest unit of code that can be exposed to Python from C++ is a function. libpy supports automatically converting C++ functions into Python functions by adapting the parameter types and return type.

libpy uses py::autofunction() to convert a C++ function into a Python function definition 1. The result of py::autofunction() can be attached to a Python module object and made available to Python.

A Simple C++ Function

Let’s start by writing a simple C++ function to expose to Python:

double fma(double a, double b, double c) {
    return a * b + c;
}

fma is a standard C++ function with no knowledge of Python.

Adapting a Function

To adapt fma into a Python function, we need to use py::autofunction().

PyMethodDef fma_methoddef = py::autofunction<fma>("fma");

py::autofunction() is a template function which takes as a template argument the C++ function to adapt. py::autofunction() also takes a string which is the name of the function as it will be exposed to Python. The Python function name does not need to match the C++ name. py::autofunction() takes an optional second argument: a string to use as the Python docstring. For example, a docstring could be added to fma with:

PyMethodDef fma_methoddef = py::autofunction<fma>("fma", "Fused Multiply Add");

Warning

Currently the name and doc string parameters must outlive the resulting PyMethodDef. In practice, this means it should be a static string, or string literal.

Adding the Function to a Module

To use an adapted function from Python, it must be attached to a module so that it may be imported by Python code. To create a Python method, we can use LIBPY_AUTOMETHOD. LIBPY_AUTOMETHOD is a macro which takes in the package name, the module name, and the set of functions to add. Following the call to LIBPY_AUTOMETHOD, we must provide a function which is called when the module is first imported. To just add functions, our body can be a simple return false to indicate that no errors occurred.

LIBPY_AUTOMODULE(libpy_tutorial, function, ({fma_methoddef}))
    (py::borrowed_ref<>) {
    return false;
}

Building and Importing the Module

To build a libpy extension, we can use setup.py and libpy’s LibpyExtension class.

In the setup.py's setup call, we can add a list of ext_modules to be built:

from libpy.build import LibpyExtension

setup(
    # ...
    ext_modules=[
        LibpyExtension(
            'libpy_tutorial.function',
            ['libpy_tutorial/function.cc'],
        ),
    ],
    # ...
)

Now, the extension can be built with:

$ python setup.py build_ext --inplace

Finally, the function can be imported and used from python:

In [1]: import libpy  # we need to ensure we import libpy before importing our extension

In [2]: from libpy_tutorial.function import fma

In [3]: fma(2.0, 3.0, 4.0)
Out[3]: 10.0

Footnotes

1

py::autofunction() creates a PyMethodDef instance, which is not yet a Python object.