boost/python/class.hpp

はじめに

<boost/python/class.hpp> は、ユーザが C++ クラスを Python へエクスポートするためのインターフェイスを定義する。class_ クラステンプレートを宣言し、その引数はエクスポートするクラス型である。また initoptional および bases ユーティリティクラステンプレートもエクスポートし、これらは class_ クラステンプレートと組み合わせて使用する。

<boost/python/class_fwd.hpp> には class_ クラステンプレートの先行宣言がある。

クラス

class_<T, Bases, HeldType, NonCopyable> クラステンプレート

template<class T, class Bases = bases<>, class HeldType = T, class NonCopyable = unspecified>
class class_ : public object

第 1 引数として渡した C++ 型に対応する Python クラスを作成する。引数は 4 つあるが、必須なのは 1 番目だけである。3 つの省略可能な引数はどのような順序でもよく、Boost.Python は引数の型から役割を判断する。

テンプレートパラメータ
  • Bases --

    ラップした T インスタンスからその直接的または間接的な基本型それぞれへの from_python 変換を登録する。多態的な各基底型 B について、間接的に保持されたラップした B インスタンスから T への変換を登録する。

    要件

    それ以前にエクスポートした T の C++ 基底クラス群を指定する bases<> の特殊化。1

    既定

    bases<>

  • HeldType --

    T のコンストラクタを呼び出したとき、または TT*ptrref 、あるいは return_internal_reference 等の CallPolicies を使用せずに Python へ変換したとき、T のインスタンスをラップする Python オブジェクトへ実際に組み込む型を指定する。詳細は後述する

    要件

    TT の派生クラス、または pointee<HeldType>::typeTT の派生クラスである Dereferenceable 型。

    既定

    T

  • NonCopyable --

    T のインスタンスをコピーする to_python 変換の自動的な登録を抑止する。T が公開アクセス可能なコピーコンストラクタを持たない場合に必要である。

    要件

    与えられた場合、boost::noncopyable でなければならない。

    既定

    boost::noncopyable 以外の未規定の型。

HeldType のセマンティクス

  1. HeldTypeT から派生している場合、そのエクスポートしたコンストラクタは、HeldType インスタンスを持つ Python オブジェクトを逆向きに参照する PyObject* を第 1 引数に受け取らなければならない()。この引数は def(init_expr) に渡される init-expression には含まれず、T の Python インスタンスが作成されるときユーザが明示的に渡すこともない。このイディオムにより、Python 側でオーバーライドする C++ 仮想関数が Python オブジェクトにアクセス可能となり、Python のメソッドが呼び出し可能となる。Boost.Python は HeldType 引数を要求するラップした C++ 関数に T のラップしたインスタンスを渡すための変換器を自動的に登録する。

  2. Boost.Python は T のラップしたインスタンスが HeldType 型の引数として渡すことを認めているため、HeldType のスマートポインタを指定することでユーザは T へのスマートポインタを受け取るところに Python の T インスタンスを渡すことができる。std::auto_ptrboost::shared_ptr<> といった対象の型を指す入れ子の element_type 型を持つスマートポインタは自動的にサポートされる。2 pointee<HeldType> を特殊化することで、他のスマートポインタ型もサポートされる。

  3. 上の 1. で述べたとおり、HeldTypeT の派生型に対するスマートポインタの場合、HeldType のエクスポートしたコンストラクタすべてで PyObject* を第 1 引数として与えなければならない。

  4. 上記 1. および 3. 以外でユーザは has_back_reference<> を特殊化することで、T 自身が第 1 引数である PyObject* で初期化されることをオプション的に指定できる。

class_ クラステンプレートの概要

namespace boost { namespace python
{
  template <class T
      , class Bases = bases<>
            , class HeldType = T
            , class NonCopyable = unspecified
           >
  class class_ : public object
  {
    // 既定の __init__ を使用するコンストラクタ
    class_(char const* name);
    class_(char const* name, char const* docstring);

    // 既定でない __init__ を指定するコンストラクタ
    template <class Init>
    class_(char const* name, Init);
    template <class Init>
    class_(char const* name, char const* docstring, Init);

    // 追加の __init__ 関数のエクスポート
    template <class Init>
    class_& def(Init);

    // メソッドの定義
    template <class F>
    class_& def(char const* name, F f);
    template <class Fn, class A1>
    class_& def(char const* name, Fn fn, A1 const&);
    template <class Fn, class A1, class A2>
    class_& def(char const* name, Fn fn, A1 const&, A2 const&);
    template <class Fn, class A1, class A2, class A3>
    class_& def(char const* name, Fn fn, A1 const&, A2 const&, A3 const&);

    // メソッドを static として宣言
    class_& staticmethod(char const* name);

    // 演算子のエクスポート
    template <unspecified>
    class_& def(detail::operator_<unspecified>);

    // 生の属性の変更
    template <class U>
    class_& setattr(char const* name, U const&);

    // データメンバのエクスポート
    template <class D>
    class_& def_readonly(char const* name, D T::*pm);

    template <class D>
    class_& def_readwrite(char const* name, D T::*pm);

    // static データメンバのエクスポート
    template <class D>
    class_& def_readonly(char const* name, D const& d);
    template <class D>
    class_& def_readwrite(char const* name, D& d);

    // プロパティの作成
    template <class Get>
    void add_property(char const* name, Get const& fget, char const* doc=0);
    template <class Get, class Set>
    void add_property(
        char const* name, Get const& fget, Set const& fset, char const* doc=0);

    template <class Get>
    void add_static_property(char const* name, Get const& fget);
    template <class Get, class Set>
    void add_static_property(char const* name, Get const& fget, Set const& fset);

    // pickle のサポート
    template <typename PickleSuite>
    self& def_pickle(PickleSuite const&);
    self& enable_pickling();
  };
}}

class_ クラステンプレートのコンストラクタ

class_(char const *name)
class_(char const *mame, char const *docstring)
template<class Init>
class_(char const *name, Init init_spec)
template<class Init>
class_(char const *name, char const *docstring, Init init_spec)
要件

name は Python の識別子の名前付け規約にしたがった ntbsdocstring が与えられた場合は ntbs でなければならない。init_spec が与えられた場合、特殊な列挙定数 no_initT と互換性のある init-expression のいずれかでなければならない。

効果

名前 name の Boost.Python 拡張クラスを保持する class_ オブジェクトを構築する。現在のスコープにおいて属性 name を新しい拡張クラスに束縛する。

  • docstring が与えられた場合、その値を拡張クラスの __doc__ 属性に束縛する。

  • init_specno_init である場合、常に Python 例外を投げる特殊な __init__ 関数を生成する。それ以外の場合は this->def(init_spec) を呼び出す。

  • init_spec が与えられなかった場合、this->def(init<>()) を呼び出す。

根拠

必要な T インスタンスを作成する __init__ 関数をエクスポートせずにラップしたメンバ関数を呼び出すことによって発生する、よくある実行時エラーを避けられるよう、class_<> コンストラクタ内でコンストラクタ引数を指定できる。

クラステンプレート class_ の変更関数

template<class Init>
class_ &def(Init init_expr)
要件

init_exprT と互換性のある init-expression の結果。

効果

Init合法な接頭辞 P それぞれについて、P を引数として受け取る拡張クラスに __init__(...) 関数の多重定義を追加する。生成された各多重定義は、上述のセマンティクスに従って init_expr の呼び出しポリシーのコピーを使用して HeldType のオブジェクトを構築する。Init合法な接頭辞の最長のものが M 個の型を有しており init_exprM 個のキーワードを保持しているとすると、各多重定義の先頭の N - M 個の引数に使用される。

戻り値

*this

根拠

ユーザはクラスのコンストラクタを容易に Python へエクスポートできる。

template<class F>
def(char const *name, Fn fn)
template<class Fn, class A1>
def(char const *name, Fn fn, A1 const &a1)
template<class Fn, class A1, class A2>
def(char const *name, Fn fn, A1 const &a1, A2 const &a2)
template<class Fn, class A1, class A2, class A3>
def(char const *name, Fn fn, A1 const &a1, A2 const &a2, A3 const &a3)
要件
効果
  • Fn の引数型列の接頭辞 P それぞれについて、その長さが A1最小引数長であるものから、拡張クラスに name(...) メソッドの多重定義を追加する。生成された各多重定義は、a1CallPolicies のコピーを使用して a1call-expressionP とともに呼び出す。A1 の合法な接頭辞の最長のものが N 個の型を有しており a1M 個のキーワードを保持しているとすると、各多重定義の先頭の N - M 個の引数に使用される。

  • それ以外の場合、fn に対してメソッドの多重定義を 1 つ構築する。Fn は null であってはならない。

    • fn が関数ポインタである場合、第 1 引数は UU cv&U cv*U cv* const& のいずれか(T*U* に変換可能とする)でなければならない。a1 から a3 が与えられた場合、下表から任意の順番であってよい。

    • 上記以外で fn がメンバ関数へのポインタである場合、参照先は T かその公開基底クラスでなければならない。a1 から a3 が与えられた場合、下表から任意の順番であってよい。

    • それ以外の場合、Fnobject かその派生型でなければならない。a1 から a2 が与えられた場合、下表の 2 行目までから任意の順番であってよい。fn呼び出し可能でなければならない。

      名前

      要件・型特性

      効果

      docstring

      ntbs

      値は結果の多重定義メソッドの __doc__ 属性に束縛される。それ以前の多重定義でドキュメンテーション文字列が与えられている場合は、改行 2 文字と新しいドキュメンテーション文字列がそこに追加される。

      policies

      CallPolicies のモデル

      結果の多重定義メソッドの呼び出しポリシーとしてコピーが使用される。

      keywords

      fn引数長を超えることがないことを指定する keyword-expression の結果。

      結果の多重定義メソッドの呼び出しポリシーとしてコピーが使用される。

戻り値

*this

class_ &staticmethod(char const *name)
要件

name は Python の識別子の名前付け規約にしたがった ntbs であり、多重定義がすべて定義済みのメソッドの名前。

効果

既存の名前 x の属性を Python の staticmethod(x) 呼び出し結果で置換する。当該メソッドが静的でありオブジェクトを渡さないことを指定する。これは以下の Python 文と等価である。

setattr(self, name, staticmethod(getattr(self, name)))
注意

staticmethod(name) 呼び出し後に def(name, ...) を呼び出すと、RuntimeError送出する

戻り値

*this

template<unspecified>
class_ &def(detail::operator_<unspecified>)
効果

ここに示す Python の特殊関数を追加する。

戻り値

*this

template<class U>
class_ &setattr(char const *name, U const &u)
要件

name は Python の識別子の名前付け規約にしたがった ntbs

効果

u を Python へ変換し、拡張クラスの属性辞書に追加する。

PyObject_SetAttrString(this->ptr(), name, object(u).ptr())
戻り値

*this

template<class Get>
void add_property(char const *name, Get const &fget, char const *doc = 0)
template<class Get, class Set>
void add_property(char const *name, Get const &fget, Set const &fset, char const *doc = 0)
要件

name は Python の識別子の名前付け規約にしたがった ntbs。 :効果: 新しい Python の property クラスインスタンスを作成し、object(fget)(2 番目の形式では object(fset) も)および(省略可能な)ドキュメンテーション文字列 doc をコンストラクタに渡す。最後にこのプロパティを構築中の Python のクラスオブジェクトに与えられた属性名 name で追加する。

戻り値

*this

根拠

ユーザは、Python の属性アクセス構文で呼び出せる関数を容易にエクスポートできる。

template<class Get>
void add_static_property(char const *name, Get const &fget)
template<class Get, class Set>
void add_static_property(char const *name, Get const &fget, Set const &fset)
要件

name は Python の識別子の名前付け規約にしたがった ntbs

効果

Boost.Python.StaticProperty オブジェクトを作成し、object(fget)(2 番目の形式では object(fset) も)をコンストラクタに渡す。最後にこのプロパティを構築中の Python のクラスオブジェクトに与えられた属性名 name で追加する。StaticProperty は先頭の self 引数なしで呼び出せる Python の property クラスの特殊な派生クラスである。

戻り値

*this

根拠

ユーザは、Python の属性アクセス構文で呼び出せる関数を容易にエクスポートできる。

template<class D>
class_ &def_readonly(char const *name, D T::* pm, char const *doc = 0)
template<class D>
class_ &def_readonly(char const *name, D const &d)
要件

name は Python の識別子の名前付け規約にしたがった ntbs

効果

それぞれ、

this->add_property(name, make_getter(pm), doc);

および

this->add_static_property(name, make_getter(d));
戻り値

*this

根拠

ユーザは、Python から自然な構文で取得可能なクラスのデータメンバや自由変数を容易にエクスポートできる。

template<class D>
class_ &def_readwrite(char const *name, D T::* pm, char const *doc = 0)
template<class D>
class_ &def_readwrite(char const *name, D &d)
効果

それぞれ、

this->add_property(name, make_getter(pm), make_setter(pm), doc);

および

this->add_static_property(name, make_getter(d), make_setter(pm));
戻り値

*this

根拠

ユーザは、Python から自然な構文で取得・設定可能なクラスのデータメンバや自由変数を容易にエクスポートできる。

template<typename PickleSuite>
class_ &def_pickle(PickleSuite const&)
要件

PickleSuitepickle_suite の公開派生型でなければならない。

効果

次の特殊な属性およびメソッドの合法な組み合わせを定義する:__getinitargs____getstate____setstate____getstate_manages_dict____safe_for_unpickling____reduce__

戻り値

*this

根拠

ユーザは、ラップしたクラスについて完全な pickle サポートを確立するための高水準インターフェイスを容易に使用できる。

class_ &enable_pickling()
効果

__reduce__ メソッドと __safe_for_unpickling__ 属性を定義する。

戻り値

*this

根拠

def_pickle の軽量な代替。Python から pickle サポートの実装を有効にする。

bases<T1, T2, ...TN> クラステンプレート

template<class ...Ts>
struct bases

class_ のインスタンス化において基底クラスのリストを記述するのに使用する MPL シーケンス

bases クラステンプレートの概要

namespace boost { namespace python
{
  template <T1 = unspecified,...Tn = unspecified>
  struct bases
  {};
}}

次のような C++ クラス宣言があるとすると、

class Foo : public Bar, public Baz
{
 public:
   Foo(int x, char const* y);
   Foo(double);

   std::string const& name() { return m_name; }
   void name(char const*);

   double value; // 公開データ
 private:
   ...
};

対応する Boost.Python 拡張クラスは以下のように作成できる。

using namespace boost::python;

class_<Foo,bases<Bar,Baz> >("Foo",
          "これは Foo のドキュメンテーション文字列。"
          "Foo 拡張クラスの記述がここに入る",

          init<int,char const*>(args("x","y"), "__init__ のドキュメンテーション文字列")
          )
   .def(init<double>())
   .def("get_name", &Foo::get_name, return_internal_reference<>())
   .def("set_name", &Foo::set_name)
   .def_readwrite("value", &Foo::value)
   ;
1

「それ以前にエクスポートした」とは bases 内の各 B について、class_<B, ...> が構築済みでなければならないという意味である。

class_<Base>("Base");
class_<Derived, bases<Base> >("Derived");
2

訳注 std::shared_ptr(C++11 以降)も自動的にサポートされます。