大橋宏正(PyDataオーガナイザー)
!pip install pybind11
Requirement already satisfied: pybind11 in /Users/wrist/.pyenv/versions/miniconda3-4.3.30/envs/py36/lib/python3.6/site-packages (2.2.4)
python setup.py build
python setup.py install
load_ext
でipybindを有効化%load_ext ipybind
PYBIND_MODULE(モジュール名, m)
m.def(公開名, 関数へのポインタ, 説明)
%%pybind11
int add(int x, int y){
return x + y;
}
PYBIND11_MODULE(myadd, m){
m.def("c_add", &add, "Add two integers.");
}
c_add(1, 2)
3
help(c_add)
Help on built-in function c_add in module pybind11_3e2e466: c_add(...) method of builtins.PyCapsule instance c_add(arg0: int, arg1: int) -> int Add two integers.
# c_add("foo", "bar")
%%pybind11
PYBIND11_MODULE(myadd, m){
m.def("lambda_add", [](int a, int b){ return a + b;},
"Add two integers.");
}
lambda_add(1, 2)
3
pybind11_add_module(myadd myadd.cpp)
py::classs_<C++クラス名>(m, 公開クラス名)
%%pybind11
namespace py = pybind11;
class Coordinate {
public:
int x_;
int y_;
Coordinate(){ x_ = 0; y_ = 0; }
Coordinate(int x, int y){ x_ = x; y_ = y; }
float Norm(){ return sqrt(x_*x_ + y_*y_); }
};
PYBIND11_MODULE(coord, m) {
py::class_<Coordinate>(m, "Coordinate")
.def(py::init<>())
.def(py::init<int, int>())
.def_readonly("x", &Coordinate::x_)
.def_readonly("y", &Coordinate::y_)
.def_property_readonly("norm", &Coordinate::Norm);
}
... .def(py::init<オーバーロード引数>())
Coordinate(){ x_ = 0; y_ = 0; }
Coordinate(int x, int y){ x_ = x; y_ = y; }
は下記のように記載
py::class_<Coordinate>(m, "Coordinate")
.def(py::init<>())
.def(py::init<int, int>())
... .def_readonly(公開変数名, メンバへのポインタ)
py::class_<Coordinate>(m, "Coordinate")
.def_readonly("x", &Coordinate::x_)
.def_readonly("y", &Coordinate::y_)
... .def_propety_readonly(公開変数名, 計算関数へのポインタ)
float Norm(){ return sqrt(x_*x_ + y_*y_); }
は
.def_property_readonly("norm", &Coordinate::Norm);
point = Coordinate(3, 4)
point
<pybind11_c19ca2a.Coordinate at 0x10ba96df8>
print(point.x, point.y)
3 4
point.norm
5.0
*arg, **kwarg
bool operator==(const Cls& rhs)
Cls.__eq__(self, other)
int.__eq__(1, 1)
True
%%pybind11
namespace py = pybind11;
class Coordinate2 {
public:
int x_; int y_;
Coordinate2(){ x_ = 0; y_ = 0; }
Coordinate2(int x, int y){ x_ = x; y_ = y; }
bool operator==(const Coordinate2& rhs){
return (x_ == rhs.x_) && (y_ == rhs.y_);
}
};
PYBIND11_MODULE(coord2, m) {
py::class_<Coordinate2>(m, "Coordinate2")
.def(py::init<>())
.def(py::init<int, int>())
.def_readonly("x", &Coordinate2::x_)
.def_readonly("y", &Coordinate2::y_)
.def("__eq__", &Coordinate2::operator==);
}
point1 = Coordinate2(3, 4)
point2 = Coordinate2(3, 4)
point3 = Coordinate2(1, 2)
point1 == point2
True
point1 == point3
False
.def("__eq__", &Coordinate2::operator==);
はc++のクラスでoperator==
が定義されていれば下記のようにも書ける
.def("__eq__",
[](const Coordinate2& self,
const Coordinate2& other){
return self == other;
});
__repr__
の定義を考える__eq__
と同様に第一引数にselfを取るメソッドを定義%%pybind11
namespace py = pybind11;
class Coordinate3 {
public:
int x_; int y_;
Coordinate3(){ x_ = 0; y_ = 0; }
Coordinate3(int x, int y){ x_ = x; y_ = y; }
};
PYBIND11_MODULE(coord3, m) {
py::class_<Coordinate3>(m, "Coordinate3")
.def(py::init<>())
.def(py::init<int, int>())
.def_readonly("x", &Coordinate3::x_)
.def_readonly("y", &Coordinate3::y_)
.def("__repr__" , [](const Coordinate3& self){
return std::string() + "(x, y) = (" + std::to_string(self.x_) + ", " + std::to_string(self.y_) + ")";
});
}
.def("__repr__", [](const Coordinate3& self){
return std::string() +
"(x, y) = (" +
std::to_string(self.x_) +
", " +
std::to_string(self.y_) + ")";
});
point = Coordinate3(1, 2)
point
(x, y) = (1, 2)
m.def
の第三引数に文字列を渡すpy::arg("...")
を渡すpy::arg("...") = デフォルト値
とすれば良い%%pybind11
namespace py = pybind11;
class Coordinate4 {
public:
int x_; int y_;
Coordinate4(){ x_ = 0; y_ = 0; }
Coordinate4(int x, int y){ x_ = x; y_ = y; }
float DistanceTo(const Coordinate4& target){
int dx = target.x_ - x_, dy = target.y_ - y_;
return sqrt( dx*dx + dy*dy);
}
};
PYBIND11_MODULE(coord4, m) {
py::class_<Coordinate4>(m, "Coordinate4")
.def(py::init<>())
.def(py::init<int, int>())
.def_readonly("x", &Coordinate4::x_)
.def_readonly("y", &Coordinate4::y_)
.def("distance_to", &Coordinate4::DistanceTo,
"distance to target",
py::arg("target"));
}
float DistanceTo(const Coordinate4& target){
int dx = target.x_ - x_, dy = target.y_ - y_;
return sqrt( dx*dx + dy*dy);
}
を下記のように設定
.def("distance_to", &Coordinate4::DistanceTo,
"distance to target",
py::arg("target"));
point = Coordinate4(1, 2)
target = Coordinate4(3, 4)
point.distance_to(target)
2.8284270763397217
point.distance_to?
*args, **kwarg
¶py::args
(py::tuple
のサブクラス)py::kwargs
(py::dict
のサブクラス)m.def("count_args", [](py::args a, py::kwargs kw) {
py::print(a.size(), "args,", kw.size(), "kwargs");
});
py::class_<Foo>(m, "Foo");
m.def("f1", [](const Foo& foo){ ...}
m.def("f2", [](py::list list){ ... }
m.def("f3", [](int x) { ... });
m.def("f4", [](const std::string& s) { ... });
m.def("f5", [](const std::vector<int>& v) { ... });
std::function
でpythonの関数を受け取れる%%pybind11
#include <pybind11/functional.h>
PYBIND11_MODULE(callback_test, m) {
m.def("for_even",
[](int n, std::function<void(int)> f) {
for (int i = 0; i < n; ++i){ if (i % 2 == 0) f(i); }
}
);
}
def py_callback_func(x):
print("called {0}".format(x))
for_even(10, py_callback_func)
called 0 called 2 called 4 called 6 called 8
#include <pybind11/numpy.h>
py::array_t<type>
型arr.ndim
, arr.shape(n)
, arr.size()
arr.data()
, arr.mutable_data()
arr.unchecked()
, arr.mutable_unchecked()
ref(i, j, k)
としてアクセス可能%%pybind11
#include <pybind11/numpy.h>
namespace py = pybind11;
PYBIND11_MODULE(numpy_bind, m) {
m.def("add_2d",
[](py::array_t<double> x, py::array_t<double> y){
auto r = x.mutable_unchecked<2>();
auto c = y.unchecked<2>();
for(ssize_t i = 0; i < r.shape(0); i++){
for(ssize_t j = 0; j < r.shape(1); j++){
r(i, j) += c(i, j);
}
}
}, py::arg().noconvert(), py::arg().noconvert());
}
import numpy as np
x = np.array([[1.0, 2.0], [3.0, 4.0]])
y = np.array([[2.0, 3.0], [4.0, 5.0]])
add_2d(x, y)
x
array([[3., 5.], [7., 9.]])