
A short introduction to
Mathieu Bernard - CoML engineers meeting 20/05/2020
https://pybind11.rtfd.io
pybind11
- wrap C++ code as python module (and vice-versa)
- fork and improvements over boost::python
- stable and widely used (pytorch, ...)
In this presentation
- wrap function and class
- numpy integration
- build system
code samples available at
https://gitlab.syntheticlearner.net/mbernard/pybind11-example
wrap a simple function
// include/add.hpp
template<class T>
T add(const T& x, const T& y)
{
return x + y;
}
// bindings/example.cpp
#include <string>
#include <pybind11/pybind11.h>
#include <add.hpp>
PYBIND11_MODULE(example, m)
{
m.doc() = "pybind11 example"; // module docstring
m.def("add_int", &add<int>, "Adds two integers");
m.def("add_float", &add<double>, "Adds two floats");
m.def("add_string", &add<std::string>, "Concat two strings");
}# Use in Python
>>> import example
>>> example.__doc__
'pybind11 example'
>>> example.add_int(2, 3)
5
>>> example.add_float(2, 3)
5.0
>>> example.add_string('to', 'to')
'toto'
# Use in Python
>>> import example
>>> example.add_string(2, 3)
TypeError: add_string(): incompatible function arguments.
The following argument types are supported:
1. (arg0: str, arg1: str) -> str
wrap a simple function (2)
// include/add.hpp
#include <algorithm>
#include <vector>
template<class T>
std::vector<T> add_vec(const std::vector<T>& x, const std::vector<T>& y)
{
std::vector<T> z(x.size());
std::transform(x.begin(), x.end(), y.begin(), z.begin(), &add<T>);
return z;
}// bindings/example.cpp
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>
#include <add.hpp>
PYBIND11_MODULE(example, m)
{
...
m.def("add_list", &add_vec<double>, "Returns the sum of two lists of float");
m.def("add_array",
[](std::vector<double> x, std::vector<double> y){
auto z = add_vec<double>(x, y);
return pybind11::array(z.size(), z.data());
});
}# Use in Python
>>> import example;
>>> example.add_list([1, 1], [2, 3])
[3, 4]# Use in Python
>>> import example; import numpy as np
>>> example.add_array(np.asarray(1, 1]), np.asarray([2, 3]))
array([3, 4])wrap a simple class
// include/counter.h
class Counter
{
public:
Counter(unsigned n = 0)
: m_count{n}
{}
unsigned count() const
{
return m_count;
}
void increment(unsigned n = 1)
{
m_count += n;
}
private:
unsigned m_count;
};// bindings/example.cpp
#include <counter.h>
...
py::class_<Counter>(m, "Counter")
.def(pybind11::init<unsigned>(), py::arg("n") = 0)
.def("count", &Counter::count, "Returns the counter value")
.def("increment", &Counter::increment,
"Increment the counter by 'n'", py::arg("n") = 1);# Usage in Python
>>> import example
>>> c = example.Counter()
>>> c.count()
0
>>> c.increment(); c.count()
1
>>> c.increment(n=2); c.count()
3
>>> import example
>>> class Doubler(example.Counter):
>>> ...: def double(self):
>>> ...: self.increment(self.count())
>>>
>>> d = Doubler(2)
>>> d.count()
2
>>> d.double(); d.count()
4
>>> d.increment(); d.count()
5build system
Project tree:
- include/ { add.hpp, counter.h }
- bindings/example.cpp
- CMakeLists.txt
- setup.py
Dependencies:
- cmake, pybind11, python-dev
- conda install cmake pybind11
Build:
- python setup.py install
create Python module example.[platform].so
# CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
project(example)
find_package(pybind11 REQUIRED)
include_directories(include)
pybind11_add_module(
example ${PROJECT_SOURCE_DIR}/bindings/example.cpp)
# setup.py
import setuptools
import setuptools.command.build_ext
class CMakeBuild(setuptools.command.build_ext.build_ext):
... # skip details
... # calls cmake as a subprocess
setuptools.setup(
name='example',
setup_requires=['cmake>=3.9'],
ext_modules=[CMakeExtension('example')],
cmdclass={'build_ext': CMakeBuild})not covered...
- copyless integration
- pointers and references
- advanced inheritance
- exceptions
- functions overload
- embed Python in C++
- ...
All details at https://pybind11.readthedocs.io
Code sample at https://gitlab.syntheticlearner.net/mbernard/pybind11-example

pybind11
By mmmaat
pybind11
A short introduction to pybind11
- 13