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::ptime
をdatetime
に変換
やりたいこと
>>> 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> >());
}