2013年1月13日日曜日

Scipy.WeaveでPythonにC++埋め込み 2 変数を渡す

変数を渡す

数値型を渡す

以下はInt型をPythonからCに渡して標準出力するメソッド例です。
def test_pass_int():
    print "---- Pass int ----"
    val = 1
    code = """
    std::cout << "val: " << val << std::endl;
    """
    weave.inline(code, ['val', ], headers=['', ])
結果は次のようになります。
---- Pass int ----
val: 1
weave.inlineの第2引数はargs=[]のオプション引数であり、Cのコード内に渡したいPython側の変数名を文字列のリストとして渡します。すると、inlineはPython側でローカル変数またはグローバル変数で使われている変数を探します。そして、見つかった変数を適切な型に変換してCコードの中で使えるようにしてくれます。上の例ではvalはPythonのPyInt型なのでC側ではそのまま使えないはずですが、ちゃんとCのint型に変換してくれます。ここでさり気なく、C++スタイルの標準出力プリントを使いました。cout, endlを使うには<iostream>が必要なので、オプション引数headersにヘッダの文字列リストを与えています。

タプルとかを渡す

タプルやリストや辞書型を渡したときにどのように扱わうか見てみます。
def test_pass_tuple():
    print "---- Pass tuple ----"
    seq = (1, 0.5, "Hoge")
    code = """
    std::cout << "length: " << seq.len() << std::endl;
    std::cout << "seq[0]: " << static_cast<int>(seq[0]) << std::endl;
    std::cout << "seq[1]: " << static_cast<double>(seq[1]) << std::endl;
    std::cout << "seq[2]: " << static_cast<char>(seq[2]) << std::endl;
    """
    weave.inline(code, ['seq', ], headers=['<iostream>', ])
数値型や文字列型以外のタプルやリストなどのオブジェクトはSCXXというPython C APIのC++ラッパーライブラリクラスに変換されます。しかし、そのまま使っているわけではなく、weave向けに独自に名前とか書き換えているっぽいです。tuple型はpy::tupleに変換されます。APIは直接weave.__file__の下のscxxフォルダにある*.hファイルを読めばすぐわかります。一応ここ( http://projects.scipy.org/scipy/browser/trunk/Lib/weave/scxx)でも見れます。py::list::operator[]でタプルの中の要素をpy::object(正確にはindexed_ref型)として取り出すことができます。py::objectには、数値型、str型、complex型の変換演算子が定義されているので、代入やキャストによって中身をCの型として取り出すことができます。
出力は以下。
---- Pass tuple ----
length: 3
seq[0]: 1
seq[1]: 0.5
seq[2]: Hoge
リストの場合もSCXXのpy::listに変換され、APIはほぼ同じです。
def test_pass_list():
    print "---- Pass list ----"
    seq = [1, 0.5, "Hoge"]
    code = """
    std::cout << "length: " << seq.len() << std::endl;
    std::cout << "seq[0]: " << static_cast<int>(seq[0]) << std::endl;
    std::cout << "seq[1]: " << static_cast<double>(seq[1]) << std::endl;
    std::cout << "seq[2]: " << static_cast<char>(seq[2]) << std::endl;
    """
    weave.inline(code, ['seq', ], headers=['<iostream>', ])
出力は以下
---- Pass list ----
length: 3
seq[0]: 1
seq[1]: 0.5
seq[2]: Hoge
辞書型はSCXXのpy::dict型に変換されます。APIも非常に簡単です。
def test_pass_dict():
    print "---- Pass dict ----"
    dct = {"PyInt":1, "PyFloat":0.5, "PyString":"Hoge"}
    code = r"""
    std::cout << "length: " << dct.len() << std::endl;
    std::cout << "dct[\"PyInt\"]: " << static_cast<int>(dct["PyInt"]) << std::endl;
    std::cout << "dct.has_key(\"PyInt\"): " << dct.has_key("PyInt") << std::endl;
    std::cout << "dct.has_key(\"PyHoge\"): " << dct.has_key("PyHoge") << std::endl;
    py::list keys = dct.keys();
    std::cout << "keys[0] : " << static_cast<char>(keys[0]) << std::endl;
    py::object tmp = py::object(634);
    dct.set_item("SkyTree", tmp);
    std::cout << "dct[\"SkyTree\"] : " << static_cast<int>(dct["SkyTree"]) << std::endl;
    """
    weave.inline(code, ['dct', ], headers=['<iostream>', ])
出力は以下。
---- Pass dict ----
length: 3
dct["PyInt"]: 1
dct.has_key("PyInt"): 1
dct.has_key("PyHoge"): 0
keys[0] : PyInt
dct["SkyTree"] : 634
例にはないですが、変数は参照として渡されているのでinlineの中で変更したdict型は呼び出し側でも変更されます。

今回は変数を渡す例をお見せしました。次回は変数を返す例を見てみます。

0 件のコメント:

コメントを投稿