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 aPyMethodDef
instance, which is not yet a Python object.