LoginSignup
13
14

More than 5 years have passed since last update.

boost.pythonで学んだあれこれ

Posted at

boost.pythonで学んだあれこれ

boost.pythonを使ってみてあれこれ学んだことを書いてみたいと思います。

モジュールのグローバル変数を追加する

やりたいこと

>>> import hoge
>>> hoge.GLOBAL_VALUE
1

boost::python::scopeを使います。

BOOST_PYTHON_MODULE(hoge)
{
    boost::python::scope().attr("GLOBAL_VALUE") = 1;
}

__str__, __repr__を定義する

やりたいこと

>>> import hoge
>>> h = hoge.hoge()
>>> print h
hoge
>>> h
hoge

いろいろやり方はあると思いますが、std::ostreamからpythonの__str__, __repr__に変換する方法です。

class hoge
{
};

std::ostream& operator<<(std::ostream& out, const hoge& )
{
    out << "hoge";
    return out;
}

BOOST_PYTHON_MODULE(hoge)
{
    using namespace boost::python;
    class_<hoge>("hoge")
    .def(self_ns::str(self))
    .def(self_ns::repr(self));
}

structのメンバにアクセスする

やりたいこと

>>> import hoge
>>> f = hoge.foo()
>>> f.a
0
>>> f.a = 5
>>> f.a
5

def_readwriteを使います。

struct foo
{
    int a;
    foo(): a(0){};
};

BOOST_PYTHON_MODULE(hoge)
{
    using namespace boost::python;
    class_<foo>("foo")
    .def_readwrite("a", &foo::a);
}

関数のデフォルト引数を使う

やりたいこと

>>> import hoge
>>> hoge.add(1)
1
>>> hoge.add(1, 2)
3
>>> hoge.add(1, 2, 3)
6

BOOST_PYTHON_FUNCTION_OVERLOADSとかBOOST_PYTHON_MEMBER_FUNCTION_OVERLOADSを使います。
BOOST_PYTHON_FUNCTION_OVERLOADS(add_overloads, add, 1, 3)addの最小引数の数を1、最大引数の数を3に設定しています。

int add(int a, int b = 0, int c = 0)
{
    return a + b + c;
}

BOOST_PYTHON_FUNCTION_OVERLOADS(add_overloads, add, 1, 3)

BOOST_PYTHON_MODULE(hoge)
{
    using namespace boost::python;
    def("add", add, add_overloads());
}

上の例を可変引数でやる

やりたいこと

>>> import hoge
>>> hoge.add(1, 2, 3, a = 4, c = 5)
>>> 15
using namespace boost::python;

int add(tuple args, dict kw)
{
    int sum = 0;
    for (int i = 0; i < len(args); ++i)
    {
    sum += extract<int>(args[i]);
    }
    list vals = kw.values();
    for (int i = 0; i < len(vals); ++i)
    {
    sum += extract<int>(vals[i]);
    }
    return sum;
}

BOOST_PYTHON_MODULE(hoge)
{
    def("add", raw_function(add));
}

boost::posix_time::ptimedatetimeに変換

やりたいこと

>>> import hoge
>>> f = hoge.foo()
>>> f.now()
datetime.datetime(2015, 12, 30, 15, 29, 12)
>>> f.now()
datetime.datetime(2015, 12, 30, 15, 29, 14)
static long get_usecs(boost::posix_time::time_duration const& d)
{
    static long resolution
    = boost::posix_time::time_duration::ticks_per_second();
    long fracsecs = d.fractional_seconds();
    if (resolution > 1000000)
    return fracsecs / (resolution / 1000000);
    else
    return fracsecs * (1000000 / resolution);
}


struct ptime_to_python_datetime
{
    static PyObject* convert(boost::posix_time::ptime const& pt)
    {
        boost::gregorian::date date = pt.date();
        boost::posix_time::time_duration td = pt.time_of_day();
        return PyDateTime_FromDateAndTime((int)date.year(),
                      (int)date.month(),
                      (int)date.day(),
                      td.hours(),
                      td.minutes(),
                      td.seconds(),
                      get_usecs(td));
    }
};

class foo
{
public:
    boost::posix_time::ptime now()
    {
    return boost::posix_time::second_clock::local_time();
    }
};

BOOST_PYTHON_MODULE(hoge)
{
    using namespace boost::python;
    PyDateTime_IMPORT;

    to_python_converter<const boost::posix_time::ptime, ptime_to_python_datetime>();

    class_<foo>("foo")
    .def("now", &foo::now);
}

structにdatetimeを持たせたい

やりたいこと

>>> import hoge
>>> import datetime
>>> h = hoge.hoge()
>>> h.date = datetime.datetime.now()
>>> h.date
datetime.datetime(2015, 12, 30, 15, 40, 6, 406588)

さっき使ったdef_readwriteは使えなくて、add_propertyを使います。

// 上の例で使ったptime_to_python_datetimeは同様に書いておく。

struct ptime_from_python_datetime
{
     ptime_from_python_datetime()
     {
         boost::python::converter::registry::push_back(&convertible,
                               &construct,
                               boost::python::type_id<boost::posix_time::ptime>());
     }

     static void* convertible(PyObject * obj_ptr)
     {
     if (!PyDateTime_Check(obj_ptr))
         return 0;
     return obj_ptr;
     }

     static void construct(PyObject* obj_ptr,
               boost::python::converter::rvalue_from_python_stage1_data * data)
     {
     PyDateTime_DateTime const* pydate
         = reinterpret_cast<PyDateTime_DateTime*>(obj_ptr);

     // Create date object
     boost::gregorian::date _date(PyDateTime_GET_YEAR(pydate),
                      PyDateTime_GET_MONTH(pydate),
                      PyDateTime_GET_DAY(pydate));

     // Create time duration object
     boost::posix_time::time_duration
         _duration(PyDateTime_DATE_GET_HOUR(pydate),
               PyDateTime_DATE_GET_MINUTE(pydate),
               PyDateTime_DATE_GET_SECOND(pydate),
               0);
     // Set the usecs value
     _duration += boost::posix_time::microseconds(PyDateTime_DATE_GET_MICROSECOND(pydate));

     // Create posix time object
     void* storage = ((boost::python::converter::rvalue_from_python_storage<boost::posix_time::ptime>*)
              data)->storage.bytes;
     new(storage) boost::posix_time::ptime(_date, _duration);
     data->convertible = storage;
     }
};

struct hoge
{
    boost::posix_time::ptime date;
};

BOOST_PYTHON_MODULE(hoge)
{
    using namespace boost::python;
    PyDateTime_IMPORT;

    ptime_from_python_datetime();
    to_python_converter<const boost::posix_time::ptime, ptime_to_python_datetime>();

    class_<hoge>("hoge")
    .add_property("date",
              make_getter(&hoge::date, return_value_policy<return_by_value>()),
              make_setter(&hoge::date, return_value_policy<copy_non_const_reference>()));

}

std::vectorを扱う

やりたいこと

>>> import hoge
>>> v = hoge.DoubleVector()
>>> v.append(1.0)
>>> v.append(2.0)
>>> v[0]
1.0
>>> v[1]
2.0

vector_indexing_suiteを使います。

BOOST_PYTHON_MODULE(hoge)
{
    using namespace boost::python;
    class_<std::vector<double> >("DoubleVector")
        .def(vector_indexing_suite<std::vector<double> >());
}

std::mapを使う

やりたいこと

>>> import hoge
>>> m = hoge.StringDoubleMap()
>>> m["a"] = 1
>>> m["b"] = 2
>>> m["a"]
1.0
>>> m["b"]
2.0

map_indexing_suiteを使います。

BOOST_PYTHON_MODULE(hoge)
{
    using namespace boost::python;
    class_<std::map<std::string, double> >("StringDoubleMap")
        .def(map_indexing_suite<std::map<std::string, double> >());
}
13
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
14