Pybind 11
Pybind 11
Pybind 11
Brian Jantzen
Unrestricted
Why??? !!!
Pybind11 - Project
• Lightweight Header-Only Library
• Exposes C++ types in Python ( & vice versa )
• Supported Compilers ( C++ 11 and higher ):
– Clang/LLVM, GCC, MSVC, Intel
• Started in 2015, currently version 2.2.+
• Copywrite, “AS-IS”
• https://github.com/pybind/pybind11
• 6.7k Stars
Pybind11 - Project
• Simple to install !!
• Simple to build !!
• Good Documentation : 150 pages
• Open unit tests : pytest
• Headers are readable!
• Support for Python 2.7, 3.x and PyPy 5.7+
• Goals and Syntax are similar to Boost Python
• Well supported and has good activity
Python Extension Choices
• Python C API ( with CPython )
• ctypes
• cffi (pypy)
• SWIG
• Cython
• Boost.Python
• Pybind11
Demo Calling C++ Functions
double cpp_add(double x, double y)
{
return x + y;
}
double cpp_sub(double x, double y)
{
return x – y;
}
Demo Calling C++ Functions
#include <pybind11/pybind11.h>
namespace py = pybind11;
using namespace py::literals;
PYBIND11_MODULE(demo1, m)
{
m.doc() = “Module to call simple cpp functions”;
• call vcvars64.bat
• Compile Command:
cl /nologo /EHsc /Ox /favor:INTEL64 /std:c++17
/Ic:\PYBIND11_PATH\include /Ic:\anaconda3\include
/c demo1.cxx
.. Or ..
set INCLUDE=%INCLUDE%;c:\PYBIND11_PATH\include;c:\anaconda3\include
cl /nologo /EHsc /Ox /favor:INTEL64 /std:c++17
/c demo1.cxx
Steps to build Python Module
• Link Command to produce pyd file
link /nologo /dll /libpath:c:\anaconda3\libs
/out:demo1.pyd demo1.obj
.. OR ..
set LIB=%LIB%;c:\anaconda3\libs
link /nologo /dll /out:demo1.pyd demo1.obj
Python
>>> from demo1 import *
>>> help(pyAdd)
Help on built-in function pyAdd in module demo1:
>>> help(pySub)
Help on built-in function pySub in module demo1:
>>> pyAdd(5,7)
12.0
>>> pySub(5,7)
-2.0
>>> pySub(y=7, x=5)
-2.0
Demo using C++ Class
class Point
{
public:
Point(double x, double y) : m_x(x), m_y(y) {}
namespace py = pybind11;
using namespace py::literals;
class Point
{
… CODE HERE …
};
PYBIND11_MODULE(demo2, m)
{
m.doc() = "Module to interact with a simple cpp class";
C++ Binding
py::class_<Point>(m, "Point")
.def(py::init<double, double>())
.def_property("x", &Point::GetX, &Point::SetX)
.def_property("y", &Point::GetY, &Point::SetY)
.def("getX", &Point::GetX)
.def("getY", &Point::GetY)
.def("__str__", &Point::toString)
.def(py::self * double())
.def("__mul__", [](const Point &p, double s)
{ return p * s; }, py::is_operator() )
.def("__repr__", [](const Point &p)
{ return "<Point x=" + std::to_string(p.GetX()) + ", " +
"y=" + std::to_string(p.GetY()) + ">"; });
}
Python
>>> from demo2 import Point
>>> p1 = Point(1.0, 2.0)
>>> p1.x, p1.y
(1.0, 2.0)
>>> p1 *= 5.0
>>> str(p1)
'[5.000000, 10.000000]'
>>> p2 = p1 * 3.
>>> p2
<Point x=15.000000, y=30.000000>
Python lists converted to std containers
… snip …
#include <pybind11/stl.h>
struct IVector {
std::vector<int> m_vector;
};
PYBIND11_MODULE(demo3, m)
{
m.doc() = "Module to demo std container";
py::class_<IVector>(m, "IVector")
.def(py::init<>())
.def_readwrite("contents", &IVector::m_vector);
}
Python
• Lists are converted to std::vector, but not returned by reference
def test_func():
list = [ 1, 2, 3, 4 ]
assert append(list, 5) == 5
assert len(list) == 4
assert list == [ 1, 2, 3, 4 ]
def test_class():
c = IVector()
c.contents = [ 1, 2, 3, 4 ]
assert len(c.contents) == 4
c.contents.append(10)
assert len(c.contents) == 4
test_demo3.py ..
Opaque std containers
… snip …
#include <pybind11/stl_bind.h>
PYBIND11_MAKE_OPAQUE(std::vector<int>);
struct IVector {
std::vector<int> m_vector;
};
PYBIND11_MODULE(demo4, m)
{
m.doc() = "Module to demo opaque std container";
py::class_<IVector>(m, "IVector")
.def(py::init<>())
.def_readwrite("contents", &IVector::m_vector);
}
Python
from demo4 import *
def test_list():
c = IList( [ 1, 2, 3, 4 ] )
assert len(c) == 4
c.append(10)
assert len(c) == 5
assert list(c) == [ 1, 2, 3, 4, 10 ]
def test_class():
c = IVector()
c.contents.extend( [ 1, 2, 3, 4 ] )
assert len(c.contents) == 4
c.contents.append(10)
assert len(c.contents) == 5
assert list(c.contents) == [ 1, 2, 3, 4, 10 ]
test_demo4.py ..
Python buffer view/numpy
class Matrix
{
public:
Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) {
m_data = new double[m_rows * m_cols];
memset(m_data, 0, sizeof(double)*m_rows*m_cols);
}
def reload_mod(module):
import _ctypes
print(_ctypes.LoadLibrary(module + '.pyd'))
print(_ctypes.LoadLibrary(module + '.pyd'))
More ++!
• Function Pointers
• Smart Pointers
• Exception
• Enumerations
• Overriding C++ classes from Python
• Native Python objects to & from C++
• Embedding the interpreter
• Gil control
Next?
Potential Usage:
• Development Tools
• Unit Testing
Presentations:
• Code & Coffee
• PyOhio Presentation?