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

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()
5

build 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++
  • ...

pybind11

By mmmaat

pybind11

A short introduction to pybind11

  • 13