Help us understand the problem. What is going on with this article?

C++のクラスをPythonで使う

More than 1 year has passed since last update.

はじめに

pybind11を使ってC++で書いたクラスをPythonで使えるようにしていきます。
また、今回の環境はmacOS High Sierraです。

pybind11のインストール

https://github.com/pybind/pybind11をcloneします。

$ git clone https://github.com/pybind/pybind11

cloneが終わったら、ビルドする前にpytestをインストールします。(pytestがないとビルドの最後にエラーが出ました。)

$ pip install pytest

pytestのインストールが終わったら以下のコマンドでビルドします。

$ cd pybind11
$ mkdir build
$ cd build
$ cmake ..
$ make check -j 2

プログラム

今回は名前、身長、体重をメンバ変数に持つPersonクラスを実装していきます。

person.h
#ifndef PERSON_H
#define PERSON_H

#include <string>

class Person
{
public:
    Person();
    Person(const std::string &name, const int &height, const int &weight);

    void SetName(const std::string &name);
    std::string GetName() const;

    void SetHeight(const int &height);
    int GetHeight() const;

    void SetWeight(const int &weight);
    int GetWeight() const;

    double GetBmi() const;
private:
    std::string mName;
    int mHeight;
    int mWeight;
};

#endif
person.cpp
#include "person.h"

Person::Person() :
        mName(""),
        mHeight(0),
        mWeight(0)
{}

Person::Person(const std::string &name, const int &height, const int &weight) :
        mName(name),
        mHeight(height),
        mWeight(weight)
{}

void Person::SetName(const std::string &name)
{
    mName = name;
}

std::string Person::GetName() const
{
    return mName;
}

void Person::SetHeight(const int &height)
{
    mHeight = height;
}

int Person::GetHeight() const
{
    return mHeight;
}

void Person::SetWeight(const int &weight)
{
    mWeight = weight;
}

int Person::GetWeight() const
{
    return mWeight;
}

double Person::GetBmi() const
{
    return mWeight / ((mHeight/100.0) * (mHeight/100.0));
}



Personクラスを実装したらpybind11でラップします。

person_wrap.cpp
#include "person.h"
#include <pybind11/pybind11.h>

namespace py = pybind11;

PYBIND11_MODULE(person, p)
{
    py::class_<Person>(p, "Person")
            .def(py::init<std::string, int, int>())
            .def_property("name", &Person::GetName, &Person::SetName)
            .def_property("height", &Person::GetHeight, &Person::SetHeight)
            .def_property("weight", &Person::GetWeight, &Person::SetWeight)
            .def("get_bmi", &Person::GetBmi)
            .def("__repr__", [](const Person &p) {
                return "Person('" + p.GetName() + "', " +
                       std::to_string(p.GetHeight()) + ", " +
                       std::to_string(p.GetWeight()) + ")";
            });
}

コンパイル

今回はcmake使ってみました。
以下のようなCMakeLists.txtを作成しました。

CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
project(person)
set(PYBIND11_CPP_STANDARD -std=c++11)
set(CMAKE_CXX_FLAGS "-Wall -O3")
set(CPLUS_INCLUDE_PATH "/usr/local/Cellar/python/3.6.4_3/Frameworks/Python.framework/Versions/3.6/include/python3.6m/")
find_package(pybind11 REQUIRED)

pybind11_add_module(person SHARED person.cpp person_wrap.cpp)

CPLUS_INCLUDE_PATHはそれぞれ書き換えて下さい。



CMakeLists.txtを作成したら以下のコマンドでコンパイルしていきます。

$ cmake .
$ make



コンパイルが終わって以下のような.soファイルができていれば問題ないです。

$ ls
CMakeCache.txt               Makefile                     person.cpython-36m-darwin.so
CMakeFiles                   cmake_install.cmake          person.h
CMakeLists.txt               person.cpp                   person_wrap.cpp

Pythonで使う

実際にPythonでインポートして動作確認してみます。

$ python
Python 3.6.4 (default, Mar  4 2018, 16:34:12)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from person import Person
>>> p = Person('tarou', 160, 40)
>>> p
Person('tarou', 160, 40)
>>> p.name = 'Tarou'
>>> p.weight = 80
>>> p
Person('Tarou', 160, 80)
>>> p.get_bmi()
31.249999999999993

最後に

最初Boostを使ってスクリプトバインディングをやってみようとしたのですが、なかなか上手くいかなかったので今回はpybind11を使ってみました。想像していたより簡単に書けたのでもうちょっと使ってみようと思います。

ksk001100
プログラム書けないマン
https://ksk.netlify.app
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away