Edited at

PythonからC++のクラスを使ってみるテスト(pybind11版)

More than 1 year has passed since last update.


概要

ctypesでextern "C"する http://qiita.com/tibigame/items/da0e50f59fb0b9fac540

のは単純な関数ならいいが、

クラスを拡張していくには不安がある。

そこでpybind11というのを試してみる。


環境


  • Windows7(64bit)

  • Anaconda (Python3.6 64bit)

  • Microsoft Visual C++ 2015 Community


準備


  1. pybind11をgitCloneしてくる。 https://github.com/pybind/pybind11

  2. includeの中にあるpybind11をフォルダごとAnacondaのincludeにコピーする。

  3. Visual Studioの追加のインクルード ディレクトリにAnacondaのincludeディレクトリを追加する。

  4. Visual Studioのリンカ―の追加の依存ファイルにAnaconda3\libs\python36.libを追加する。

  5. ビルドはx64, Releaseに設定する。


C++コード


ClassTestLib.cpp

#define NOMINMAX

#define _CRT_SECURE_NO_WARNINGS

#include "stdafx.h"
#include <pybind11/pybind11.h>
namespace py = pybind11;

class ClassTest {
public:
int a;
int *b;
ClassTest() {
}
ClassTest(int X) {
a = X;
b = new int;
*b = X * 2;
}
~ClassTest() {
delete b;
}
int calcA(int add) {
return a + add;
}
int getB() {
return *b;
}
};

PYBIND11_PLUGIN(ClassTestLib) {
py::module m("ClassTestLib", "pybind11 example plugin");
py::class_<ClassTest>(m, "ClassTest")
.def(py::init<const int>())
.def("calcA", &ClassTest::calcA)
.def("getB", &ClassTest::getB);
return m.ptr();
}



ポイント

この二行を定義しておかないとビルドが止まる。


  • #define NOMINMAX

  • #define CRT_SECURE_NOWARNINGS

共有DLLでMFCを使用するにしないとcmathとかの関数使うと落ちる。

スタティックよりは共有のが若干速い。

class部分は前のコードをそのままコピペしてきた。

Cでexternしてた部分がPYBIND11_PLUGIN('ファイル名')に置き換わった。

ビルド後に「ClassTestLib.dll」を「ClassTestLib.pyd」にリネームして

pythonコードがあるディレクトリにコピーする。


Pythonコード


classTest.py

import ClassTestLib

x = ClassTestLib.ClassTest(100)
print (x.calcA(10))
print (x.getB())


結果

110

200

PYBIND11_PLUGINの書き方はイマイチわかっていない。

デストラクタがどうなるのかとか、

複雑な引数、返り値の時にうまく書けるんだろうかという心配はあるが、

ずいぶんとクラスっぽく使えるようになったのでよしとする。