C++クラスをpythonへ公開する

http://svn.sourceforge.jp/svnroot/shive/junk/diary/2009/20091215boostpython.tar.gz
詳細は↑こちらを参照。

// src\person.cpp
#include "stdafx.h"

class Person
{
public:
    Person() {
        printf("[%08X]Person.ctor\r\n", (uintptr_t)this);
    }
    virtual ~Person() {
        printf("[%08X]Person.dtor\r\n", (uintptr_t)this);
    }
    void say() {
        printf("[%08X]hello!!\r\n", (uintptr_t)this);
    }

    Person* getThisAsPointer() {
        return this;
    }
    Person& getThisAsReference() {
        return *this;
    }
};

BOOST_PYTHON_MODULE(person)
{
    using namespace boost::python;

    class_<Person>("Person", "<<< document here >>>")
        .def("say", &Person::say)
        .def("getThisAsPointer", &Person::getThisAsPointer, return_value_policy<return_opaque_pointer>())
        .def("getThisAsReference", &Person::getThisAsReference, return_internal_reference<>());
}

return_value_policy()とreturn_internal_reference<>()がミソ。

# test.py

from person import *
p0 = Person()
print 'type(p0) ->', type(p0)
print 'p0.say() ->',
p0.say()

p1 = p0.getThisAsPointer()
print 'type(p1) ->', type(p1)
try:
    print 'p1.say() ->',
    p1.say()
except:
    print 'except!!'

p2 = p0.getThisAsReference()
print 'type(p2) ->', type(p2)
print 'p2.say() ->',
p2.say()

ビルドしてテスト

$ scons -Q test
python test.py
fibo(40) -> 102334155
[00CD4850]Person.ctor
type(p0) -> <class 'person.Person'>
p0.say() ->[00CD4850]hello!!
 type(p1) -> <type 'class Person *'>
p1.say() -> except!!
type(p2) -> <class 'person.Person'>
p2.say() ->[00CD4850]hello!!

[00CD4850]Person.dtor

アドレスがちゃんと同じですね。getThisAsPointerの方はポインタ型が返ってくるのでメソッドは呼び出せないご様子。ハンドル渡しとかはポインタ型を使うのかな?

余談

tar.gzの中にはこの前のfiboのコードも混ざってますが気にしない。
pythonモジュールはinithoge/hoge.pydのように名前が一致していないといけないようなのですが、2つビルドするのが面倒だったので同じモジュールをリネームしてます。
sayの改行コードが微妙にズレて出るのは何で何だろう?まぁいいか。