添字アクセスのサポート
ヘッダ <boost/python/indexing/indexing_suite.hpp> 、ヘッダ <boost/python/indexing/vector_indexing_suite.hpp>
はじめに
indexing は、添字アクセス可能(indexable)な C++ コンテナを Python へ容易にエクスポートするための Boost.Python の機能である。添字アクセス可能なコンテナとは operator[]
によりランダムアクセス可能なコンテナである(例:std::vector
)。
std::vector
のようなどこにでもある添字アクセス可能な C++ コンテナを Python へエクスポートするのに必要な機能は Boost.Python はすべて有しているが、その方法はあまり直感的ではない。Python のコンテナから C++ コンテナへの変換は容易ではない。Python のコンテナを Boost.Python を使用して C++ 内でエミュレート(Python リファレンスマニュアルの「コンテナ型をエミュレートする」を見よ)するのは簡単ではない。C++ コンテナを Python へ変換する以前に考慮すべきことが多数ある。これには __len__
、__getitem__
、__setitem__
、__delitem__
、__iter__
および __contains__
メソッドに対するラッパ関数の実装が含まれる。
目的は、
添字アクセス可能な C++ コンテナの振る舞いを、Python コンテナの振る舞いに一致させる。
c[i] が変更可能であるといった、コンテナ要素のインデクス(
__getitem__
)に対する既定の参照セマンティクスを提供する。要件は以下のとおり(m
は非 const(可変)メンバ関数(メソッド))。val = c[i] c[i].m() val == c[i]
__getitem__
から安全な参照を返す:後でコンテナに追加、コンテナから削除しても懸垂参照が発生しない(Python をクラッシュさせない)。スライスの添字をサポート。
適切な場合は Python のコンテナ引数(例:
list
、tuple
)を受け付ける。再定義可能なポリシークラスによる拡張性。
ほとんどの STL および STL スタイルの添字アクセス可能なコンテナに対する定義済みサポートを提供する。
Boost.Python の indexing インターフェイス
indexing_suite[ヘッダ <boost/python/indexing/indexing_suite.hpp>]
indexing_suite
クラスは、Python に調和させる C++ コンテナを管理するための基底クラスである。目的は C++ コンテナの外観と振る舞いを Python コンテナのそれに一致させることである。このクラスは自動的に(Python リファレンスの「コンテナ型をエミュレートする」の)Python の特殊メソッドをラップする。
__len__
(self
)組み込み関数
len
を実装するために呼び出される。オブジェクトの長さ(0 以上の整数)を返さなければならない。また__nonzero__
メソッドを定義せず__len__
メソッドが 0 を返すオブジェクトは、論理値の文脈で偽として扱われる。__getitem__
(self
,key
)self[key]
の評価を実装するために呼び出される。シーケンス型では、受け取るキーは整数およびスライスオブジェクトでなければならない。負の添字に対する特殊な解釈(クラスがシーケンス型をエミュレートする場合)は__getitem__
メソッドの仕事であることに注意していただきたい。key
が不適な型な場合はTypeError
を送出し、値が(負の値に対する特殊な解釈の後)シーケンスの添字の集合外である場合はIndexError
を送出しなければならない。注意:シーケンスの終了を適切に検出するため、for
ループは不正な添字に対してIndexError
が送出することを想定している。__setitem__
(self
,key
,value
)self[key]
への代入を実装するために呼び出される。注意すべき点は__getitem__
と同じである。このメソッドは、マップ型についてはオブジェクトがキーに対する値の変更をサポートするか新しいキーを追加可能な場合、シーケンス型については要素が置換可能な場合のみ実装すべきである。不適なkey
値に対しては__getitem__
メソッドと同様の例外を送出しなければならない。__delitem__
(self
,key
)self[key]
の削除を実装するために呼び出される。注意すべき点は__getitem__
と同じである。このメソッドは、マップ型についてはオブジェクトがキーの削除をサポートする場合、シーケンス型については要素をシーケンスから削除可能な場合のみ実装すべきである。不適なkey
値に対しては__getitem__
メソッドと同様の例外を送出しなければならない。__iter__
(self
)このメソッドは、コンテナに対してイテレータが要求されたときに呼び出される。このメソッドは、コンテナ内のすべてのオブジェクトを走査する新しいイテレータオブジェクトを返さなければならない。マップ型については、コンテナのキーを走査しなければならず、
iterkeys
メソッドとしても利用可能でなければならない。イテレータオブジェクトもまたこのメソッドを実装する必要があり、自分自身を返さなければならない。イテレータオブジェクトの詳細については、Python ライブラリリファレンスの「イテレータ型」を見よ。
__contains__
(self
,item
)メンバ関係テスト操作を実装するために呼び出される。
self
内にitem
があれば真を、そうでなければ偽を返さなければならない。マップ型オブジェクトについては、値やキー・値の組ではなくキーを対象とすべきである。
indexing_suite の派生クラス
indexing_suite
はそのままで使用することを意図していない。indexing_suite
の派生クラスにより 2 、3 のポリシー関数を提供しなければならない。しかしながら、標準的な添字アクセス可能な STL コンテナのための indexing_suite
派生クラス群が提供されている。ほとんどの場合、単に定義済みのクラス群を使用すればよい。場合によっては必要に応じて定義済みクラスを改良してもよい。
vector_indexing_suite[ヘッダ <boost/python/indexing/vector_indexing_suite.hpp>]
vector_indexing_suite
クラスは、std::vector
クラス(および std::vector
スタイルのクラス(例:std::vector
のインターフェイスを持つクラス))をラップするために設計された定義済みの indexing_suite
派生クラスである。indexing_suite
が要求するポリシーをすべて提供する。
class X {...};
...
class_<std::vector<X> >("XVec")
.def(vector_indexing_suite<std::vector<X> >())
;
XVec
は完全な Python コンテナとなる(完全な例と Python のテストも見よ)。
map_indexing_suite[ヘッダ <boost/python/indexing/map_indexing_suite.hpp>]
map_indexing_suite
クラスは、std::map
クラス(および std::map
スタイルのクラス(例:std::map
のインターフェイスを持つクラス))をラップするために設計された定義済みの indexing_suite
派生クラスである。indexing_suite
が要求するポリシーをすべて提供する。
class X {...};
...
class_<std::map<X> >("XMap")
.def(map_indexing_suite<std::map<X> >())
;
既定では添字アクセスした要素はプロキシで返される。NoProxy
テンプレート引数で true
を与えるとこれは無効化できる。XMap
は完全な Python コンテナとなる(完全な例と Python のテストも見よ)。
indexing_suite クラス
-
template<class Container, class DerivedPolicies, bool NoProxy = false, bool NoSlice = false, class Data = typename Container::value_type, class Index = typename Container::size_type, class Key = typename Container::value_type>
class indexing_suite : unspecified - テンプレートパラメータ
Container --
Python に対してラップするコンテナ型。
- 要件
クラス型
DerivedPolicies --
ポリシーフックを提供する派生クラス群。以下の DerivedPolicies を見よ。
- 要件
indexing_suite
の派生クラス
NoProxy --
既定では添字アクセスした要素は Python の参照のセマンティクスを持ち、プロキシにより返される。これは
NoProxy
テンプレート引数に真を与えることで無効化できる。- 要件
論理値
- 既定
false
NoSlice --
スライスを許可しない。
- 要件
論理値
- 既定
false
Data --
コンテナのデータ型。
- 既定
Container::value_type
Index --
コンテナの添字型。
- 既定
Container::size_type
Key --
コンテナのキー型。
- 既定
Container::value_type
template < class Container , class DerivedPolicies , bool NoProxy = false , bool NoSlice = false , class Data = typename Container::value_type , class Index = typename Container::size_type , class Key = typename Container::value_type > class indexing_suite : unspecified { public: indexing_suite(); // デフォルトコンストラクタ }
DerivedPolicies
派生クラスは indexing_suite
が必要なフックを提供する。
data_type&
get_item(Container& container, index_type i);
static object
get_slice(Container& container, index_type from, index_type to);
static void
set_item(Container& container, index_type i, data_type const& v);
static void
set_slice(
Container& container, index_type from,
index_type to, data_type const& v
);
template <class Iter>
static void
set_slice(Container& container, index_type from,
index_type to, Iter first, Iter last
);
static void
delete_item(Container& container, index_type i);
static void
delete_slice(Container& container, index_type from, index_type to);
static size_t
size(Container& container);
template <class T>
static bool
contains(Container& container, T const& val);
static index_type
convert_index(Container& container, PyObject* i);
static index_type
adjust_index(index_type current, index_type from,
index_type to, size_type len
);
これらのポリシーの大部分は自己説明的であるが、convert_index
と adjust_index
は少し説明が必要である。
convert_index
は Python の添字をコンテナが処理可能な C++ の添字に変換する。例えば Python における負の添字は右から数え始める(例:C[-1]
は C
内の最も右の要素を差す)。convert_index
は C++ コンテナのために必要な変換を処理しなければならない(例:-1
は C.size() - 1 である)。convert_index
はまた、添字の型(Python の動的型)を C++ コンテナが想定する実際の型に変換できなければならない。
コンテナが拡張か縮小すると、要素への添字はデータの移動に追従して調整しなければならない。例えば 5 要素から成るベクタの 0 番目(a)から 3 つの要素を削除すると、添字 4 は添字 1 となる。
[a][b][c][d][e] ---> [d][e]
^ ^
4 1
adjust_index
の仕事は調整である。添字 current
を与えると、この関数はコンテナにおける添字 from
..to
におけるデータを len
個の要素で置換したときの調整後の添字を返す。
vector_indexing_suite クラス
-
template<class Container, bool NoProxy = false, class DerivedPolicies = unspecified_default>
class vector_indexing_suite : unspecified_base - テンプレートパラメータ
Container --
Python に対してラップするコンテナ型。
- 要件
クラス型
NoProxy --
既定では添字アクセスした要素は Python の参照のセマンティクスを持ち、プロキシにより返される。これは
NoProxy
テンプレート引数に真を与えることで無効化できる。- 要件
論理値
- 既定
false
DerivedPolicies --
vector_indexing_suite
はさらに定義済みのポリシーに派生している可能性がある。CRTP(James Coplien の「奇妙に再帰したテンプレートパターン」、C++ レポート、1995 年 2 月)を介した静的な多態により基底クラスindexing_suite
が最派生クラスのポリシー関数を呼び出せる。- 要件
indexing_suite
の派生クラス
template < class Container, bool NoProxy = false, class DerivedPolicies = unspecified_default > class vector_indexing_suite : unspecified_base { public: typedef typename Container::value_type data_type; typedef typename Container::value_type key_type; typedef typename Container::size_type index_type; typedef typename Container::size_type size_type; typedef typename Container::difference_type difference_type; data_type& get_item(Container& container, index_type i); static object get_slice(Container& container, index_type from, index_type to); static void set_item(Container& container, index_type i, data_type const& v); static void set_slice(Container& container, index_type from, index_type to, data_type const& v); template <class Iter> static void set_slice(Container& container, index_type from, index_type to, Iter first, Iter last); static void delete_item(Container& container, index_type i); static void delete_slice(Container& container, index_type from, index_type to); static size_t size(Container& container); static bool contains(Container& container, key_type const& key); static index_type convert_index(Container& container, PyObject* i); static index_type adjust_index(index_type current, index_type from, index_type to, size_type len); };
map_indexing_suite クラス
-
template<class Container, bool NoProxy = false, class DerivedPolicies = unspecified_default>
class map_indexing_suite : unspecified_base - テンプレートパラメータ
Container --
Python に対してラップするコンテナ型。
- 要件
クラス型
NoProxy --
既定では添字アクセスした要素は Python の参照のセマンティクスを持ち、プロキシにより返される。これは
NoProxy
テンプレート引数に真を与えることで無効化できる。- 要件
論理値
- 既定
false
DerivedPolicies --
map_indexing_suite
はさらに定義済みのポリシーに派生している可能性がある。CRTP(James Coplien の「奇妙に再帰したテンプレートパターン」、C++ レポート、1995 年 2 月)を介した静的な多態により基底クラスindexing_suite
が最派生クラスのポリシー関数を呼び出せる。- 要件
indexing_suite
の派生クラス
template < class Container, bool NoProxy = false, class DerivedPolicies = unspecified_default > class map_indexing_suite : unspecified_base { public: typedef typename Container::value_type value_type; typedef typename Container::value_type::second_type data_type; typedef typename Container::key_type key_type; typedef typename Container::key_type index_type; typedef typename Container::size_type size_type; typedef typename Container::difference_type difference_type; static data_type& get_item(Container& container, index_type i); static void set_item(Container& container, index_type i, data_type const& v); static void delete_item(Container& container, index_type i); static size_t size(Container& container); static bool contains(Container& container, key_type const& key); static bool compare_index(Container& container, index_type a, index_type b); static index_type convert_index(Container& container, PyObject* i); };