ユーザの作った python object を C++ に渡す(4) | Chandler@Berlin

Chandler@Berlin

ベルリン在住

self.face_idx_list へのアクセス方法.extracting a numpy.int64 type failed

前回と違うのは,numpy.array には numpy.float64 ではなく,numpy.int64 が入っている点である.しかし.numpy.float64 は,

vec[i] = boost::python::extract< float >(
    float32_3_obj.attr("__getitem__")(i));

つまり, boost::python::extract< float >(f) で float 値に変換できた.しかし,numpy.int64を

vec[i] = boost::python::extract< int >(
    int32_3_obj.attr("__getitem__")(i));

つまり,boost::python::extract< int >(i) で int 値に変換しようとするとできないのである.そうしようとすると,

 TypeError: No registered converter was able to produce a C++ rvalue of
 type int from this Python object of type numpy.int64.

というエラーに出会うことになる.これに関しては web を探してみると,http://boost.2283326.n4.nabble.com/extracting-a-numpy-int32-type-td2701573.html という記事があった.どうやら numpy では numpy.float64 から float への converter が register されているのだが,numpy.int64 に関しては 64bit マシンではそういう converter がないようだ.python の世界では int(i) を使えばいいとあるが,C++の世界ではそうはいかない.そこで以下のようなトリックを使う.

int vec[] = {0, 0, 0};
for(int i = 0; i < 3; ++i){
    object int64_obj = int32_3_obj.attr("__getitem__")(i);
    vec[i] = boost::python::extract< int >(
        int64_obj.attr("__int__")());
}

このトリックは一度 numpy.int64 を python の object として取り出し,その attribute にある int への変換メンバを使う.

ここでヒントを一つ.どうやったらそんな変換関数があるのがわかるのだろうか?それは python のオブジェクト自身に尋ねることができる.python の object のattribute はそれ自身 python のシーケンスとして見ることができる.つまり,python の interpreter から, type() を使うと以下のような出力が得られる.

>>> import numpy
>>> a = numpy.array([1,2,3])
>>> type(a[0])
<type 'numpy.int64'>

つまり numpy.array の要素は 'int' ではなく, numpy.int64 であることがわかる.このタイプの object も python の object であるから,どんな attributeを持っているかは, dir()を使えば見ることができる.そうすると,intへの変換が用意されていることがわかる.それを使ってみよう.

>>> type(a[0].__int__())
<type 'int'>

今度は 'int' が取り出せた.この object なら extract< int >で C++ の intが取り出せる.

基本的にここにあるようにすれば,ユーザ側で定義した python の内容を C++に渡すことができる.

この情報が誰かの役に立ったら嬉しいです.