pybind11ことはじめ
目次
- 1. 概要
- 2. 関連文書
- 3. 環境構築(Dockerを利用して)
- 4. 本家の文書のFirst stepsをやってみる
- 5. CMakeで前章の内容をやってみる
- 6. classを利用その1
- 7. classを利用その2
- 8. コンテナを利用(std::vector) 1
- 9. コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例)
- 10. コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う)
- 11. コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う)
- 12. 引数に名前をつける
- 13. 引数にデフォルト値を設定
- 14. 変数のエクスポート
- 15. オーバーロードされたメソッド
- 16. モジュール名に注意
- 17. 今後
- 18. この文書のチェンジログ
1 概要
- C++11をPythonで利用しやすくするツールの一種
- ヘッダーファイルのみで構成されている
- DlibのPythonとの連携で使われていて調べた
2 関連文書
- GitHub https://github.com/pybind/pybind11
- Setuptools example https://github.com/pybind/python_example
- Scikit-build example https://github.com/pybind/scikit_build_example
- CMake example https://github.com/pybind/cmake_example
- 文書 https://pybind11.readthedocs.io/en/stable/index.html
- First steps https://pybind11.readthedocs.io/en/stable/basics.html
- STL containers https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html
- Binding STL containers https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html?highlight=stl#binding-stl-containers
- Local STL container bindings https://pybind11.readthedocs.io/en/stable/upgrade.html?highlight=stl#local-stl-container-bindings
- Classes https://pybind11.readthedocs.io/en/stable/advanced/classes.html
- Classes module-local https://pybind11.readthedocs.io/en/stable/advanced/classes.html#module-local
- Instance and static fields https://pybind11.readthedocs.io/en/stable/classes.html#instance-and-static-fields
- Binding lambda functions https://pybind11.readthedocs.io/en/stable/classes.html#binding-lambda-functions
- CMake helpers https://pybind11.readthedocs.io/en/stable/cmake/index.html
- Building with setuptools https://pybind11.readthedocs.io/en/stable/compiling.html#building-with-setuptools
- Building with CMake https://pybind11.readthedocs.io/en/stable/compiling.html#building-with-cmake
- Building manually https://pybind11.readthedocs.io/en/stable/compiling.html#building-manually
- Building with Bazel https://pybind11.readthedocs.io/en/stable/compiling.html#building-with-bazel
- 類似のツール
3 環境構築(Dockerを利用して)
- 色々なOS(Windows,Mac,Linux)で、同じ操作で出来るように、Dockerを利用して環境を作る
- Docker無しで、必要なツールをインストールして直接やってもOK(その場合この章はスキップ)
- 必要なツール
- C++のコンパイラ
- CMake
- GNU Make
- Python とヘッダーファイル、ライブラリファイル
- Python のライブラリ
- pip
- pybind11
- あった方が良いもの
- git
- Python のライブラリ
- ipython
- 必要なツール
3.1 以下の操作を行っている動画
3.2 環境構築(Dockerを利用して)の手順
3.2.1 事前準備
- OSに依存せずに同じ環境作れるようにDockerを利用してこの動画シリーズやっていきます。
- まずDockerをインストールしてください。
- 私はUbuntu20.04の環境で行って行きます。DockerはWindowsやMacでも使えるので、他のOSでもDockerを入れれば同じ手順で出来ます。
- Docker等でUbuntuの環境を用意
- Python,Python-dev,c++コンパイラー,cmake,git等必要なパッケージインストール
- 以下のコマンドで、共有用のディレクトリ作成し、user idを1000にしておく
sudo mkdir -p /work/pybind11 sudo chown 1000.1000 /work/pybind11
3.2.2 DockerのUbuntu20.04を利用して毎回必要なパッケージを入れる場合
- ubuntu20.04を起動する
- Docker内の/homeを/work/pybind11と共有
docker run -it --rm -v /work/pybind11:/home/ ubuntu:20.04
3.2.3 pybind11を利用するのに必要なパッケージを入れたDockerイメージを作成する場合
- Dockerfileの準備
- 以下の内容でDockerfileを作成
FROM ubuntu:20.04 MAINTAINER NM Max ENV user_n=user ENV user_id=1000 #ENV DEBIAN_FRONTEND=noninteractive RUN apt -y update \ && apt -y upgrade \ && echo "6\n79\n" | apt -y install tzdata RUN apt -y install python3-dev python3-pip vim git g++ clang cmake make w3m less python3-ipython ipython3 nkf less diffutils patch sudo zlib1g-dev unzip locales \ && locale-gen ja_JP.UTF-8 \ && pip3 install pybind11 ENV LC_ALL ja_JP.UTF-8 ENV LANG ja_JP.UTF-8 ENV LANGUAGE LANGUAGE=ja_JP:ja RUN echo 'LANG="ja_JP.UTF-8"' >> /etc/default/locale RUN echo "${user_n} ALL=NOPASSWD: ALL" >> /etc/sudoers WORKDIR /work RUN echo "\n\n\n\n\n\n\n" | adduser --uid ${user_id} --disabled-password ${user_n} RUN echo "user ALL=NOPASSWD: ALL" >> /etc/sudoers && chown user.user /work RUN mkdir -p /home/${user_n}/C && chown ${user_n}.${user_n} /home/${user_n}/C ENTRYPOINT sudo su - ${user_n}
- 以下のコマンドでイメージ作成
docker build -t mypybind11 .
- 作成したDockerイメージの起動は以下のコマンドで
docker run -it --rm -v /work/pybind11:/home/user/C mypybind11
3.3 この章のまとめ
- どのOSでも共通で利用できる環境をDockerで作成
- Dockerの環境の準備が面倒なら、必要なツールをインストールして直接やってもよい
4 本家の文書のFirst stepsをやってみる
- 前の章で準備したDocker環境内でpybind11を使ってみる
4.1 以下の操作を行っている動画
4.2 本家の文書のFirst stepsをやる手順
4.2.1 事前準備
- OSに依存せずに同じ環境作れるようにDockerを利用してこの動画シリーズやっていきます。
- まずDockerをインストールしてください。
- 私はUbuntu20.04の環境で行って行きます。DockerはWindowsやMacでも使えるので、他のOSでもDockerを入れれば同じ手順で出来ます。
- Docker等でUbuntuの環境を用意
- Python,Python-dev,c++コンパイラー,cmake,git等必要なパッケージインストール
- 前の章で作成したmypybind11イメージを利用する場合
- 前の章で作成した専用Dockerイメージmypybind11を起動
- /work/pybind11 を Docker内の/homeと共通にしてます。
docker run -it --rm -v /work/pybind11:/home/user/C mypybind11
- 起動したDocker環境内で以下を実行
- ubuntu20.04の場合は cd /home/user/C ではなく cd /home で
cd /home/user/C mkdir test001 cd test001/ pwd
- /home/user/C/test001 と表示され、現在の作業しているディレクトリを確認できます。
- 前の章で作成した専用Dockerイメージmypybind11を起動
- 前の章で作成したmypybind11イメージを利用せずにUbuntu20.04を利用する場合
- この場合、必要なものが入ってないので、Dockerイメージ起動あとに、必要なものを入れる必要があります。
docker run -it --rm -v /work/pybind11:/home Ubuntu20.04
- 以下を実行して必要なパッケージを入れる
apt update apt upgrade apt install python3-dev python3-pip vim git g++ clang cmake make w3m less python3-ipython ipython3 pip3 install pybind11
- 起動したDocker環境内で以下を実行
- ubuntu20.04の場合は cd /home/user/C ではなく cd /home で
cd /home/ mkdir test001 cd test001/ pwd
- /home/test001 と表示され、現在の作業しているディレクトリを確認できます。
4.2.2 example.cppの準備
- First steps https://pybind11.readthedocs.io/en/stable/basics.htmlにあるexample.cppをコピペ
4.2.3 コンパイル
c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
4.2.4 動作確認
- 対話環境で動作確認した方がやりやすいので、IPythonを起動する
ipython3
- 作成したモジュールの読み込み
import example
- 1+2をやってみる
example.add(1,2)
- 1+2で3が表示されます
- 次に5+6をやってみる。
example.add(5,6)
- 5+6で11が表示されます
4.3 この章のまとめ
- 本家文書のFirst stepsをやってみた
- 使い方の基本の確認
- C++で作成した関数をPythonで利用する手順の理解
5 CMakeで前章の内容をやってみる
- 前の章で準備したDocker環境内でpybind11を使ってみる
- 関係文書
- Building with CMake https://pybind11.readthedocs.io/en/stable/compiling.html#building-with-cmake
5.1 以下の操作を行っている動画
5.2 cmakeで前章の内容をやってみる手順
5.2.1 事前準備
- 必要なソフトを入れる
- 前の章のexample.cppを入れておく
- example.cppのあるディレクトリに移動
5.2.2 CMakeLists.txt の準備
- Building with CMake https://pybind11.readthedocs.io/en/stable/compiling.html#building-with-cmake にあるのをそのまま利用
cmake_minimum_required(VERSION 3.4...3.18) project(example LANGUAGES CXX) add_subdirectory(pybind11) pybind11_add_module(example example.cpp)
5.2.3 コンパイル
- https://pybind11.readthedocs.io/en/stable/basics.htmlの手順
- make check -j 4 と文書になってるけど make で作成
mkdir build
cd build
cmake ..
make
- 前の章と同じ手順で動作確認すべき
5.3 この章のまとめ
- 前章の内容をcmakeを利用してやってみた
- コンパイルがちょい楽に
6 classを利用その1
- 関係文書
- Classes https://pybind11.readthedocs.io/en/stable/advanced/classes.html
- Classes module-local https://pybind11.readthedocs.io/en/stable/advanced/classes.html#module-local
- Instance and static fields https://pybind11.readthedocs.io/en/stable/classes.html#instance-and-static-fields
- Classes https://pybind11.readthedocs.io/en/stable/advanced/classes.html
6.1 以下の操作を行っている動画
6.2 classを利用その1の手順
- この動画で以前作成したDockerイメージを起動
- 作業用ディレクトリにてCMakeLists.txtとexample.cppの2つを用意
6.2.1 以前作成したDockerイメージの起動
docker run -it --rm -v /work/pybind11:/home/user/C mypybind11
6.2.2 作業用のディレクトリの作成と移動
cd /home/user/C mkdir test002 cd test002/ pwd
6.2.3 CMakeLists.txt の作成
- 前の章で利用したものを使う
- Building with CMake https://pybind11.readthedocs.io/en/stable/compiling.html#building-with-cmake にあるのをそのまま利用
cmake_minimum_required(VERSION 3.4...3.18) project(example LANGUAGES CXX) add_subdirectory(pybind11) pybind11_add_module(example example.cpp)
6.2.4 example.cppの作成
- 前の章で利用したものに簡単なクラスTest01を追加
- Class Test01をPython側で利用出来るようにコード追加
- def_readwrite でpublicのメンバ変数を参照してPythonから使えるようにした
- コンストラクタと、helloメンバ関数を参照してPythonから使えるようにした
#include <pybind11/pybind11.h> #include <string> namespace py = pybind11; int add(int i, int j) { return i + j; } class Test01 { public: Test01(const std::string &s) { name=s; } std::string name; std::string hello() { return "Hello "+name+"!"; } }; // https://pybind11.readthedocs.io/en/stable/classes.html#instance-and-static-fields // https://pybind11.readthedocs.io/en/stable/classes.html#binding-lambda-functions PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring m.def("add", &add, "A function which adds two numbers"); py::class_<Test01>(m, "Test01") .def(py::init<const std::string &>()) .def_readwrite("name", &Test01::name) .def("hello", &Test01::hello); }
6.2.5 pybind11の最新をgitでゲット
git clone https://github.com/pybind/pybind11
6.2.6 コンパイル
- 以前の章と同じコマンド
- https://pybind11.readthedocs.io/en/stable/basics.htmlの手順
- make check -j 4 と文書になってるけど make で作成
mkdir build
cd build
cmake ..
make
6.2.7 動作確認
- ipythonを起動して確認すると対話形式なので色々試しやすい
import example m=example.Test01("Tom") m.name m.hello()
- 次の章でオブジェクトを文字列化するところをカスタマイズするので、一度表示してみる。
m
- 内部の情報とかは現状見れない。次の章でここらの表現をカスタマイズします。
- 次の章で、ダイナミックに属性を追加出来るようにするので、現在出来ないことを確認
m.age=32
- AttributeError: ‘example.Test01’ object has no attribute ‘age’ が表示される
6.3 この章のまとめ
- classをやってみた。
7 classを利用その2
- 追加で以下をやる
- クラスオブジェクトを表示した時の表現をカスタマイズ
- __dict__で情報表示
- 関係文書
- Classes https://pybind11.readthedocs.io/en/stable/advanced/classes.html
- Classes module-local https://pybind11.readthedocs.io/en/stable/advanced/classes.html#module-local
- Instance and static fields https://pybind11.readthedocs.io/en/stable/classes.html#instance-and-static-fields
- Binding lambda functions https://pybind11.readthedocs.io/en/stable/classes.html#binding-lambda-functions
- Classes https://pybind11.readthedocs.io/en/stable/advanced/classes.html
7.1 以下の操作を行っている動画
7.2 classを利用その2の手順
- この動画で以前作成したDockerイメージを起動
- 作業用ディレクトリにてCMakeLists.txtとexample.cppの2つを用意
7.2.1 以前作成したDockerイメージの起動
docker run -it --rm -v /work/pybind11:/home/user/C mypybind11
7.2.2 作業用のディレクトリの作成と移動
cd /home/user/C mkdir test003 cd test003/ pwd
7.2.3 CMakeLists.txt の作成
- 前の章で利用したものと同じ
- Building with CMake https://pybind11.readthedocs.io/en/stable/compiling.html#building-with-cmake にあるのをそのまま利用
cmake_minimum_required(VERSION 3.4...3.18) project(example LANGUAGES CXX) add_subdirectory(pybind11) pybind11_add_module(example example.cpp)
7.2.4 example.cppの作成
- 前の章で利用したものに多少修正
- Class Test01のpybind11用記述部分に2箇所追加
- py::dynamic_attr()追加 これにより 動的に属性追加可能に。 dict でそれらの情報出てくる。
- .def(“repr“, …. 部分追加 これにより、クラスオブジェクトの表示をカスタマイズ
- py::dynamic_attr()追加 これにより 動的に属性追加可能に。 dict でそれらの情報出てくる。
- Class Test01のpybind11用記述部分に2箇所追加
#include <pybind11/pybind11.h> #include <string> namespace py = pybind11; int add(int i, int j) { return i + j; } class Test01 { public: Test01(const std::string &s) { name=s; } std::string name; std::string hello() { return "Hello "+name+"!"; } }; PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring m.def("add", &add, "A function which adds two numbers"); py::class_<Test01>(m, "Test01", py::dynamic_attr()) .def(py::init<const std::string &>()) .def_readwrite("name", &Test01::name) .def("hello", &Test01::hello) .def("__repr__", [](const Test01 &a) { return "<example.Test01 named '" + a.name + "'>"; } ); }
7.2.5 pybind11の最新をgitでゲット
git clone https://github.com/pybind/pybind11
7.2.6 コンパイル
- 以前の章と同じコマンド
- https://pybind11.readthedocs.io/en/stable/basics.htmlの手順
- make check -j 4 と文書になってるけど make で作成
mkdir build
cd build
cmake ..
make
7.2.7 動作確認
- ipythonを起動して確認すると対話形式なので色々試しやすい
import example m=example.Test01("Tom") m.name m.hello()
- 次の章でオブジェクトを文字列化するところをカスタマイズするので、一度表示してみる。
m
- 表示がカスタマイズされて、nameの情報が表示されるようになった
- 動的に属性を追加出来るようになっているので、試す。
m.age=32 m.age print(m.__dict__)
- 内部情報が表示されるようになった。
7.3 さらなる使い方
- 以下にさらなる情報があるので、そこの例を動かす事をオススメします。(これらも文書化や動画化するかもしないかも)
7.4 この章のまとめ
- 前章のClassに動的に属性を追加出来るようにした。
- 前章のClassを文字列化した時の表現のカスタマイズを行った。
8 コンテナを利用(std::vector) 1
- 関係文書
- STL containers https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html
- Binding STL containers https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html?highlight=stl#binding-stl-containers
- Local STL container bindings https://pybind11.readthedocs.io/en/stable/upgrade.html?highlight=stl#local-stl-container-bindings
8.1 以下の操作を行っている動画
8.2 コンテナを利用(std::vector) 1 の手順
- この動画で以前作成したDockerイメージを起動
- 作業用ディレクトリにてCMakeLists.txtとexample.cppの2つを用意
8.2.1 以前作成したDockerイメージの起動
docker run -it --rm -v /work/pybind11:/home/user/C mypybind11
8.2.2 作業用のディレクトリの作成と移動
cd /home/user/C mkdir test004 cd test004/ pwd
8.2.3 CMakeLists.txt の作成
- 前の章で利用したものと同じ
- Building with CMake https://pybind11.readthedocs.io/en/stable/compiling.html#building-with-cmake にあるのをそのまま利用
cmake_minimum_required(VERSION 3.4...3.18) project(example LANGUAGES CXX) add_subdirectory(pybind11) pybind11_add_module(example example.cpp)
8.2.4 example.cppの作成
- pybind11/stl.h をインクルード
- C++ で2つの関数を定義
- range関数,最初、最後、差を与えると、等差数列をかえす関数
- 無限ループ回避の処理をいれたら、ちょい不細工に
- concatv 2つの整数(int)の数列を結合してかえす関数
- range関数,最初、最後、差を与えると、等差数列をかえす関数
- Pythonに渡す関数の記述
- 2つの関数の記述
#include <pybind11/pybind11.h> #include <pybind11/stl.h> #include <vector> namespace py = pybind11; std::vector<int> range(int st, int end, int diff) { std::vector<int> ans; bool flag=(end-st)*diff>=0; if(flag && diff!=0) { if(end>=st) { for(int i=st;i<=end;i+=diff) { ans.push_back(i); } } else { for(int i=st;i>=end;i+=diff) { ans.push_back(i); } } } else { ans.push_back(st); } return ans; } std::vector<int> concatv(const std::vector<int> &a, const std::vector<int> &b) { std::vector<int> ans; for(int i=0;i<a.size();++i) { ans.push_back(a[i]); } for(int i=0;i<b.size();++i) { ans.push_back(b[i]); } return ans; } PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring m.def("range", &range, "A function which make a arithmetic progression"); m.def("concatv", &concatv, "A function which concatenate two int vector"); }
8.2.5 pybind11の最新をgitでゲット
git clone https://github.com/pybind/pybind11
8.2.6 コンパイル
- 以前の章と同じコマンド
- https://pybind11.readthedocs.io/en/stable/basics.htmlの手順
- make check -j 4 と文書になってるけど make で作成
mkdir build
cd build
cmake ..
make
8.2.7 動作確認
- ipythonを起動して確認すると対話形式なので色々試しやすい
import example example.range(1,10,1) example.range(1,10,2) example.range(10,1,-1) example.range(1,10,-1) example.range(1,10,0) example.concatv([5,6],[1,2,3]) example.concatv([1,2,3],[4,5])
8.3 この章のまとめ
- std::vectorを使ったC++関数をPython側から使えるようにしてみた。
9 コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例)
- Making opaque types https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#making-opaque-types の例をやってみる。
- 関係文書
- Making opaque types https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#making-opaque-types
- STL containers https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html
- Binding STL containers https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html?highlight=stl#binding-stl-containers
- Local STL container bindings https://pybind11.readthedocs.io/en/stable/upgrade.html?highlight=stl#local-stl-container-bindings
9.1 以下の操作を行っている動画
9.2 コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例) の手順
9.2.1 以前作成したDockerイメージの起動
docker run -it --rm -v /work/pybind11:/home/user/C mypybind11
9.2.2 作業用のディレクトリの作成と移動
cd /home/user/C mkdir test005 cd test005/ pwd
9.2.3 CMakeLists.txt の作成
- 前の章で利用したものと同じ
- Building with CMake https://pybind11.readthedocs.io/en/stable/compiling.html#building-with-cmake にあるのをそのまま利用
cmake_minimum_required(VERSION 3.4...3.18) project(example LANGUAGES CXX) add_subdirectory(pybind11) pybind11_add_module(example example.cpp)
9.2.4 example.cppの作成
- このままコピペじゃ動かないので、不足分を追加して実際に動かしてみる - この例は意図した動作になっていない。自分でも同じことする時は気をつけるべき
- 意図する動作にする手順は次の章で
#include <pybind11/pybind11.h> #include <pybind11/stl.h> #include <vector> namespace py = pybind11; void append_1(std::vector<int> &v) { v.push_back(1); } class MyClass { public: std::vector<int> contents; }; /* ... binding code ... */ PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring m.def("append_1", &append_1); py::class_<MyClass>(m, "MyClass") .def(py::init<>()) .def_readwrite("contents", &MyClass::contents); }
9.2.5 pybind11の最新をgitでゲット
git clone https://github.com/pybind/pybind11
9.2.6 コンパイル
- 以前の章と同じコマンド
- https://pybind11.readthedocs.io/en/stable/basics.htmlの手順
- make check -j 4 と文書になってるけど make で作成
mkdir build
cd build
cmake ..
make
9.2.7 動作確認
- ipythonを起動して確認すると対話形式なので色々試しやすい
import example v=[1,2,3] example.append_1(v) v
- [1,2,3,1]ではなく[1,2,3]がかえってくる
- クラスの方もやってみる
m = example.MyClass() m.contents = [5, 6] m.contents m.contents.append(7) m.contents
- これも[5,6,7]ではなく[5,6]がかえってくる
9.3 この章のまとめ
- Making opaque types https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#making-opaque-types の意図しない動作になる例をやってみた。
- これを回避するにはOPAQUEを使う。回避例は次の章で。
10 コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う)
- Making opaque types https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#making-opaque-types の例をやってみる。
- 関係文書
- Making opaque types https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#making-opaque-types
- STL containers https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html
- Binding STL containers https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html?highlight=stl#binding-stl-containers
- Local STL container bindings https://pybind11.readthedocs.io/en/stable/upgrade.html?highlight=stl#local-stl-container-bindings
10.1 以下の操作を行っている動画
10.2 コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う)手順
- 手順は前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。
10.2.1 example.cppの作成
- https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#making-opaque-typesにある例
- ../pybind11/tests/test_opaque_types.cpp を参考に
- push_backを追加(std::vector<int>用に修正)
- print_opaque_list(std::vector<int>用に修正)
#include <pybind11/pybind11.h> #include <pybind11/stl.h> #include <vector> #include <string> namespace py = pybind11; void append_1(std::vector<int> &v) { v.push_back(1); } class MyClass { public: std::vector<int> contents; }; /* ... binding code ... */ PYBIND11_MAKE_OPAQUE(std::vector<int>); PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring py::class_<std::vector<int>>(m, "IntVector") .def(py::init<>()) .def("clear", &std::vector<int>::clear) .def("pop_back", &std::vector<int>::pop_back) .def("push_back", (void (std::vector<int>::*)(const int &)) &std::vector<int>::push_back) .def("__len__", [](const std::vector<int> &v) { return v.size(); }) .def("__iter__", [](std::vector<int> &v) { return py::make_iterator(v.begin(), v.end()); }, py::keep_alive<0, 1>()); /* Keep vector alive while iterator is used */ m.def("print_opaque_list", [](const std::vector<int> &l) { std::string ret = "Opaque list: ["; bool first = true; for (auto entry : l) { if (!first) ret += ", "; ret += std::to_string(entry); first = false; } return ret + "]"; }); m.def("append_1", &append_1); py::class_<MyClass>(m, "MyClass") .def(py::init<>()) .def_readwrite("contents", &MyClass::contents); }
10.2.2 動作確認
import example m=example.MyClass() example.print_opaque_list(m.contents) m.contents.push_back(1) m.contents.push_back(2) example.print_opaque_list(m.contents) example.append_1(m.contents) example.print_opaque_list(m.contents) example.append_1(m.contents) example.print_opaque_list(m.contents)
10.3 この章のまとめ
- Making opaque types https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#making-opaque-types の意図しない動作になる例をOPAQUEを使って修正して動かしてみた。
11 コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う)
- Binding STL containers https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#binding-stl-containers
- Making opaque types https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#making-opaque-types の例をやってみる。
- 関係文書
- Making opaque types https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#making-opaque-types
- STL containers https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html
- Binding STL containers https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html?highlight=stl#binding-stl-containers
- Local STL container bindings https://pybind11.readthedocs.io/en/stable/upgrade.html?highlight=stl#local-stl-container-bindings
11.1 以下の操作を行っている動画
11.2 コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う) 手順
- 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。
11.2.1 example.cppの作成
- Binding STL containers https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#binding-stl-containersにある例
- https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#making-opaque-typesにある例
- このままコピペじゃ動かないので、不足分を追加して実際に動かしてみる - この例は意図した動作になっていない。自分でも同じことする時は気をつけるべき
- 意図する動作にする手順は次の章で
- ../pybind11/tests/test_opaque_types.cpp を参考に
- push_backを追加(std::vector<int>用に修正)
- print_opaque_list(std::vector<int>用に修正)
#include <pybind11/pybind11.h> #include <pybind11/stl_bind.h> #include <vector> #include <string> namespace py = pybind11; void append_1(std::vector<int> &v) { v.push_back(1); } class MyClass { public: std::vector<int> contents; }; /* ... binding code ... */ PYBIND11_MAKE_OPAQUE(std::vector<int>); PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring py::bind_vector<std::vector<int>>(m, "VectorInt"); m.def("append_1", &append_1); py::class_<MyClass>(m, "MyClass") .def(py::init<>()) .def_readwrite("contents", &MyClass::contents); }
11.2.2 動作確認
import example m=example.MyClass() m.contents m.contents=example.VectorInt([1,2,3]) example.append_1(m.contents) m.contents m.contents.append(5) m.contents
11.3 この章のまとめ
- Making opaque types https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html?highlight=std%3A%3Avector#making-opaque-types の意図しない動作になる例を Binding STL containers を使って修正して動かしてみた。
12 引数に名前をつける
- First steps https://pybind11.readthedocs.io/en/stable/basics.html の Keyword arguments https://pybind11.readthedocs.io/en/latest/basics.html#keyword-arguments の例をやってみる
- 関係文書
- First steps https://pybind11.readthedocs.io/en/stable/basics.html
- Keyword arguments https://pybind11.readthedocs.io/en/latest/basics.html#keyword-arguments
12.1 以下の操作を行っている動画
12.2 引数に名前をつける手順
- 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。
- Dockerイメージの起動からコンパイルまでの手順は以前の動画 https://www.youtube.com/embed/fBW69-x4n6U を参考にやってください。
12.2.1 example.cppの作成
- First steps https://pybind11.readthedocs.io/en/stable/basics.html の Keyword arguments https://pybind11.readthedocs.io/en/latest/basics.html#keyword-arguments の例をやってみる
- 引数に名前つけないのが、コメントアウトした行の内容
- pyを使うため、namespaceの行追加
#include <pybind11/pybind11.h> namespace py = pybind11; int add(int i, int j) { return i + j; } PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring // m.def("add", &add, "A function which adds two numbers"); // org m.def("add", &add, "A function which adds two numbers", py::arg("i"), py::arg("j")); }
12.2.2 動作確認
import example example.add(i=1,j=2)
12.3 この章のまとめ
- Keyword arguments https://pybind11.readthedocs.io/en/latest/basics.html#keyword-arguments の例をやってみた。
- 引数名のつけ方がわかった
13 引数にデフォルト値を設定
- First steps https://pybind11.readthedocs.io/en/stable/basics.html の Default arguments https://pybind11.readthedocs.io/en/latest/basics.html#default-arguments
- 関係文書
- First steps https://pybind11.readthedocs.io/en/stable/basics.html
- Default arguments https://pybind11.readthedocs.io/en/latest/basics.html#default-arguments
13.1 以下の操作を行っている動画
13.2 引数にデフォルト値を設定する手順
- 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。
- Dockerイメージの起動からコンパイルまでの手順は以前の動画 https://www.youtube.com/embed/fBW69-x4n6U を参考にやってください。
13.2.1 example.cppの作成
- First steps https://pybind11.readthedocs.io/en/stable/basics.html の Default arguments https://pybind11.readthedocs.io/en/latest/basics.html#default-arguments
- 前の章との差
- デフォルト値を記述追加
#include <pybind11/pybind11.h> namespace py = pybind11; int add(int i, int j) { return i + j; } PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring // m.def("add", &add, "A function which adds two numbers"); // org // m.def("add", &add, "A function which adds two numbers", py::arg("i"), py::arg("j")); // 前の章 m.def("add", &add, "A function which adds two numbers", py::arg("i")=1, py::arg("j")=2); }
13.2.2 動作確認
import example example.add(i=2) example.add(j=3) example.add()
13.3 この章のまとめ
- Default arguments https://pybind11.readthedocs.io/en/latest/basics.html#default-arguments の例をやってみた。
- 引数のデフォルト値の設定方法を知れた
14 変数のエクスポート
- First steps https://pybind11.readthedocs.io/en/stable/basics.html の Exporting variableshttps://pybind11.readthedocs.io/en/latest/basics.html#exporting-variablesの例をやってみる
- 関係文書
- First steps https://pybind11.readthedocs.io/en/stable/basics.html
- Exporting variableshttps://pybind11.readthedocs.io/en/latest/basics.html#exporting-variables
14.1 以下の操作を行っている動画
14.2 変数のエクスポート 手順
- 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。
- Dockerイメージの起動からコンパイルまでの手順は以前の動画 https://www.youtube.com/embed/fBW69-x4n6U を参考にやってください。
14.2.1 example.cppの作成
- First steps https://pybind11.readthedocs.io/en/stable/basics.html の Exporting variableshttps://pybind11.readthedocs.io/en/latest/basics.html#exporting-variablesの例をやってみる
- 前の章との差
- デフォルト値を記述追加
#include <pybind11/pybind11.h> namespace py = pybind11; PYBIND11_MODULE(example, m) { m.attr("the_answer") = 42; py::object world = py::cast("World"); m.attr("what") = world; }
14.2.2 動作確認
import example example.the_answer example.the_answer=53 example.the_answer example.what example.what="hoho" example.what
14.3 この章のまとめ
- First steps https://pybind11.readthedocs.io/en/stable/basics.html の Exporting variableshttps://pybind11.readthedocs.io/en/latest/basics.html#exporting-variablesの例をやってみた
15 オーバーロードされたメソッド
- 関係文書
- Overloaded methods https://pybind11.readthedocs.io/en/stable/classes.html#overloaded-methods
15.1 以下の操作を行っている動画
15.2 オーバーロードされたメソッドをPythonで利用する手順
- C++14以前の方法と、C++14以降とでやり方2つある
- C++14以降の方が記述が楽なので、こっちだけ動画で説明します。(もう一つの方法は Overloaded methods https://pybind11.readthedocs.io/en/stable/classes.html#overloaded-methodsをご覧ください)
- pybind11では自動で、それらのメソッドを自動で選択してくれない、なので、ひとつひとつ引数を記述して記述していく
- Dockerイメージの起動からコンパイルまでの手順は以前の動画 https://www.youtube.com/embed/fBW69-x4n6U を参考にやってください。
15.2.1 C++ソースファイルの作成
- Overloaded methods https://pybind11.readthedocs.io/en/stable/classes.html#overloaded-methods のサンプルソースだけだとコンパイルして動かせないので、不足分を追加して、動くようにしたのが以下
- example.cpp という名前でお好きなテキストエディタでファイルを作成
#include <pybind11/pybind11.h> namespace py = pybind11; struct Widget { int foo(int x, float y) { return x+y; } int foo(int x, float y) const { return x-y; } }; PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring py::class_<Widget>(m, "Widget") .def(py::init<>()) .def("foo_mutable", py::overload_cast<int, float>(&Widget::foo)) .def("foo_const", py::overload_cast<int, float>(&Widget::foo, py::const_)); }
15.2.2 CMakeLists.txt の作成
- 前の章で利用したものとほぼ同じ
- Building with CMake https://pybind11.readthedocs.io/en/stable/compiling.html#building-with-cmake にあるのをそのまま利用
- それにC++14を利用するように環境設定3つ設定追加
cmake_minimum_required(VERSION 3.4...3.18) set(CMAKE_CXX_STANDARD 14) # C++14以上に設定する set(CMAKE_CXX_STANDARD_REQUIRED ON) # 設定のC++のバージョン条件を満たせないならエラーにする set(CMAKE_CXX_EXTENSIONS OFF) # 互換性を高める project(example LANGUAGES CXX) add_subdirectory(pybind11) pybind11_add_module(example example.cpp)
15.2.3 pybind11の最新をgitでゲット
git clone https://github.com/pybind/pybind11
15.2.4 コンパイル
- 以前の章と同じコマンド
mkdir build
cd build
cmake ..
make
15.2.5 動作確認
- ipythonを起動して確認すると対話形式なので色々試しやすい
import example w=example.Widget() w.foo_mutable(1,2) w.foo_const(1,2)
15.3 この章のまとめ
- オーバーロードされたメソッドの取扱方法の1つを行なった。
16 モジュール名に注意
- CMakeLists.txt内のモジュール名とc++ソースのモジュール名が異ると、コンパイルは可能なのですが、モジュール読み込み時にエラーが発生
- Dockerイメージの起動からコンパイルまでの手順は以前の動画 https://www.youtube.com/embed/fBW69-x4n6U を参考にやってください。
16.1 以下の操作を行っている動画
16.2 モジュール名に注意 の確認手順
- 前のソースのCMakeLists.txtの pybind11_add_module(example example.cpp) を pybind11_add_module(widget example.cpp) とか、別名にしてみる
- コンパイルしなおして、モジュール読み込むと以下のエラーが発生
--------------------------------------------------------------------------- ImportError Traceback (most recent call last) <ipython-input-1-64ca027457b3> in <module> ----> 1 import widget ImportError: dynamic module does not define module export function (PyInit_widget)
- ということで、 CMakeLists.txt内のモジュール名と、C++ソースのモジュール名同じにする必要があります。(こないだこれでハマり、時間ロスしました)
16.3 この章のまとめ
- CMakeLists.txt のモジュール名と、C++ソースで記述したモジュール名は同じにしましょう。そうしないとエラー発生。
17 今後
- 今後も文書追加していきます。
18 この文書のチェンジログ
- 2021/05/08 初版
- 2021/05/10 classを利用その1 の章, classを利用その2 の章追加
- 2021/05/10 Dockerイメージの起動のコマンドに誤りがあったので修正
- 2021/05/11 コンテナを利用(std::vector) 1 の章追加
- 2021/05/12 コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例) の章、コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う) の章、 * コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う) の章追加
- 2021/05/13 引数に名前をつける の章、 引数にデフォルト値を設定 の章、 変数のエクスポート の章追加
- 2021/05/21 オーバーロードされたメソッド の章追加, モジュール名に注意 の章追加
- 2021/05/24 BlogへのアップロードをMarkDownに変換して登録するように変更
Created: 2021-05-24 月 23:42