fc2ブログ
PyCXXの簡単な例
MacOSX10.5のPython2.6で動かせる簡単なPyCXXの例を、貼り付けておきます。

test.cxx

#ifdef _MSC_VER
// disable warning C4786: symbol greater than 255 character,
// nessesary to ignore as <map> causes lots of warning
#pragma warning(disable: 4786)
#endif

#include "CXX/Objects.hxx"
#include "CXX/Extensions.hxx"

class test_module : public Py::ExtensionModule<test_module>{
public:
test_module():Py::ExtensionModule<test_module>( "test" ){
add_varargs_method("func", &test_module::func2, "test function2");
initialize( "this is the test module" );
}

virtual ~test_module()
{}

private:

Py::Object func2 (const Py::Tuple &args){
Py::List res = args[0];
res.append(Py::Float(args[1]));
std::cout << res[-1] << std::endl;
return res;
}

};

extern "C" void inittest()
{
#if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL)
Py::InitialisePythonIndirectPy::Interface();
#endif

static test_module* test = new test_module;
}

// symbol required for the debug version
extern "C" void inittest_d()
{ inittest(); }


mac_py26.mak

#
# Build the example on Mac OS X for version 2.6
#
CC=gcc -arch i386
CCC=g++ -arch i386
CCCFLAGS=-c -g -fPIC -I/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6 -I.
LDSHARED=$(CCC) -bundle -g -u _PyMac_Error -F/Library/Frameworks -framework System \
/Library/Frameworks/Python.framework/Versions/2.6/Python
LDLIBS=
PYTHON=/Library/Frameworks/Python.framework/Versions/2.6/Resources/Python.app/Contents/MacOS/Python

COMMON_OBJECTS=cxxsupport.o cxx_extensions.o cxxextensions.o IndirectPythonInterface.o
MY_OBJECTS=test.o

all: test.so

#
# my object
#
test.so: $(MY_OBJECTS) $(COMMON_OBJECTS)
$(LDSHARED) -o $@ $(MY_OBJECTS) $(COMMON_OBJECTS) $(LDLIBS)

test.o: test.cxx
$(CCC) $(CCCFLAGS) -o $@ $<

#
# common objects
#
cxxsupport.o: Src/cxxsupport.cxx
$(CCC) $(CCCFLAGS) -o $@ $<

cxx_extensions.o: Src/cxx_extensions.cxx
$(CCC) $(CCCFLAGS) -o $@ $<

cxxextensions.o: Src/cxxextensions.c
$(CC) -c $(CCCFLAGS) -o $@ $<

IndirectPythonInterface.o: Src/IndirectPythonInterface.cxx
$(CCC) $(CCCFLAGS) -o $@ $<

#
# Clean rule
#
clean:
rm -f *.o
rm -f test.so

どちらも、サンプルファイルをちょっと変更してわかりやすくしただけですが、これだけで結構Py::Listの動きなどよくわかると思います。

~/pycxx-6.1.1$ make -f mac_py26.mak

で、test.soができていることを確認して、インタラクティブシェルを起動します。

~/pycxx-6.1.1$ python
Python 2.6.3 (r263:75184, Oct  2 2009, 07:56:03)
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import test
>>> l = test.func(range(3),10)
10.0
>>> l
[0, 1, 2, 10.0]
>>> type(l)
<type 'list'>
>>>

という具合に使えます。
C++でコードを書くとき、ラッパーオブジェクトをどのあたりまで使ったらいいのかとか、本格的なプログラミングには、すこし考えが必要ですかね。
スポンサーサイト



テーマ:プログラミング - ジャンル:コンピュータ

【2009/10/27 17:58】 | Python | トラックバック(0) | コメント(0) | page top↑
C++でPythonを拡張したい!
最近よく使っているRandom ForestsやNMF(non-negative matrix factorization)などの単純な繰り返し計算が多いアルゴリズムを実装すると、どうしてもPythonでは満足な実行速度が得られません。そういうときは、C++を使うんですが、タブ区切りのデータファイルを読み込んで2次元配列にするとか、そういう処理はC++じゃなくて、Pythonで書きたいわけです。
これまでも、PyscoやPyrexでの高速化を試してきたわけですが、やっぱりC++で書いたモジュールを

>>> import hello
>>> hello.foo()

などとして使えると、かっこいいなーと思い、C++でPythonを拡張する方法をいくつか試してみました。
日本語でも詳しいページがいくつかあって、こちらはその代表格です。

Boostはよく使うので、Boost.pythonの存在は知っていて、Boostというブランドイメージもあり、良いものに違いないと思い、使って見ましたが、私にはどうもうまく使いこなせませんでした。簡単なC++のモジュールもMacOSXの環境でコンパイル出来ません。
そもそもbjamの使い方がわからないのですが、これに関しては同じことを言っている人がいらっしゃって、makeファイルを公開してくれています。いろいろいじって、コンパイルは通るようになったけど、インタラクティブシェルでimportするとエラーになったりと、どうにもこうにもうまく動かせる気配がなく、あきらめムードが漂ってきました。
やっぱり、SWIGか?と思い、こちらも試してみることに。SWIGは様々な言語からC/C++へのアクセスを可能にする仕組みで、とくにPythonとは相性がよいようです。こちらがもっとも簡単な紹介ページのようですが、なんか気に入りませんでした。いや、きっと良いものなんだろうと思うんですが、どうもしっくりきません。
ctypesは、Pythonに標準で装備されている機能なので、良いのでしょうが使い方が不格好過ぎてやる気が出ません。きっと、これは既存のC/C++で書かれたライブラリをそのままPythonで使うための手段でしょう。必要な部分だけをC++で作るという今回の目的とは少しずれているので、見送りです。

そうこうしていると、PyCXXなるものを見つけてしまいました。Googleで探してもあまり関連情報や紹介記事が無く、大丈夫なのかこれ?と疑ったりもしましたが、結局これをしばらく使ってみることにしました。どうやらPythonCライブラリをC++へ拡張したもののようで、まあ何より最初の導入がエラー無くうまく行ったのが採用の最大の理由です。
最新のバージョンは、6.1.1ですが、これをダウンロードし、解凍します。pycxx-6.1.1ディレクトリに移動するとREADME.htmlがありますので、指示に従ってください。
Python2.6が入ったMacOSXでは、sudo python setup.py installでインストールした後、

~/pycxx-6.1.1$ make -f example_mac_py26.mak example.so

としてモジュールをコンパイルした後、Pythonインタラクティブシェルを起動しモジュールをimportします。

>>> import example
range object created 0xa16930
range object destroyed 0xa16930
>>> dir(example)
['__doc__', '__file__', '__name__', '__package__', 'a_constant', 'kw', 'range', 'string', 'sum', 'test']
>>> example.test()
Example Test starting
Trying to convert a NULL to an Py::Int
Correctly caught
Py::Exception value: PyCXX: Error creating object of type N2Py6ObjectE from (nil)
Py::Exception traceback: None
以下省略

などと、動きます。
あとは、Demo/Python2/example.cxx
を見ながら適当に改変するなり、コピーして自分のモジュールを作ればOK。
Pythonのオブジェクトをスマートにラップしてくれているので、少しさわってみた感触では、とっても使いやすそうです。
Boostでの拡張モジュールのビルドには苦しめられ続けたので、きっとPyCXXの方が簡単なんじゃないかなーと思っていたら、ここに投稿しているlucさんも同じようなことを言っていて、PyCXXの知名度がもう少しあがってもいいんじゃないかなーと思っています。かなりお勧めです。

テーマ:プログラミング - ジャンル:コンピュータ

【2009/10/23 18:35】 | Python | トラックバック(0) | コメント(0) | page top↑
| ホーム |