10.7 バッファオブジェクト構造体 (buffer object structure)

バッファインタフェースは、あるオブジェクトの内部データを一連の データチャンク (chunk) として見せるモデルを外部から利用できるようにします。 各チャンクはポインタ/データ長からなるペアで指定します。 チャンクはセグメント(segment) と呼ばれ、 メモリ内に不連続的に配置されるものと想定されています。

バッファインタフェースを利用できるようにしたくないオブジェクト では、PyTypeObject 構造体の tp_as_buffer メンバを NULLにしなくてはなりません。利用できるようにする場合、 tp_as_bufferPyBufferProcs 構造体を 指さねばなりません。

注意: PyTypeObject 構造体の tp_flags メンバ の値を 0 でなく Py_TPFLAGS_DEFAULT に しておくことがとても重要です。この設定は、 PyBufferProcs 構造体に bf_getcharbuffer スロットが入っていることを Python ランタイムに教えます。 Python の古いバージョンには bf_getcharbuffer メンバが 存在しないので、古い拡張モジュールを使おうとしている新しいバージョンの Python インタプリタは、このメンバがあるかどうかテストしてから 使えるようにする必要があるのです。

PyBufferProcs
バッファプロトコルの実装を定義している関数群へのポインタを 保持するのに使われる構造体です。

最初のスロットはbf_getreadbuffer で、 getreadbufferproc 型です。 このスロットが NULLの場合、オブジェクトは内部データの 読み出しをサポートしません。そのような仕様には意味がないので、 実装を行う側はこのスロットに値を埋めるはずですが、呼び出し側では 非 NULL の値かどうかきちんと調べておくべきです。

次のスロットは bf_getwritebuffer で、 getwritebufferproc 型です。オブジェクトが返すバッファに 対して書き込みを許可しない場合はこのスロットをNULL にできます。

第三のスロットは bf_getsegcount で、 getsegcountproc 型です。このスロットは NULL であっては ならず、オブジェクトにいくつセグメントが入っているかを呼び出し側に 教えるために使われます。PyString_TypePyBuffer_Type オブジェクトのような単純なオブジェクトには単一のセグメントしか入って いません。

最後のスロットは bf_getcharbuffer で、 getcharbufferproc です。オブジェクトの PyTypeObject 構造体における tp_flags フィールドに、 Py_TPFLAGS_HAVE_GETCHARBUFFER ビットフラグがセットされている 場合にのみ、このスロットが存在することになります。 このスロットの使用に先立って、呼び出し側は PyType_HasFeature() を使ってスロットが存在するか調べねばなりません。 フラグが立っていても、bf_getcharbufferNULLのときもあり、 NULLはオブジェクトの内容を 8 ビット文字列 として利用できない ことを示します。 このスロットに入る関数も、オブジェクトの内容を 8 ビット文字列に 変換できない場合に例外を送出することがあります。例えば、 オブジェクトが浮動小数点数を保持するように設定されたアレイの場合、 呼び出し側が bf_getcharbuffer を使って 8 ビット文字列 としてデータを取り出そうとすると例外を送出するようにできます。 この、内部バッファを ``テキスト'' として取り出すという概念は、 本質的にはバイナリで、文字ベースの内容を持ったオブジェクト間の 区別に使われます。

注意: 現在のポリシでは、文字 (character) はマルチバイト文字 でもかまわないと決めているように思われます。従って、 サイズ N のバッファが N 個のキャラクタからなる とはかぎらないことになります。

Py_TPFLAGS_HAVE_GETCHARBUFFER
型構造体中のフラグビットで、bf_getcharbuffer スロットが 既知の値になっていることを示します。このフラグビットがセット されていたとしても、オブジェクトがバッファインタフェースをサポート していることや、bf_getcharbuffer スロットが NULLでない ことを示すわけではありません。

Py_ssize_t (*getreadbufferproc) (PyObject *self, Py_ssize_t segment, void **ptrptr)
*ptrptrの中の読み出し可能なバッファセグメントへのポインタを返します。 この関数は例外を送出してもよく、送出する場合には -1 を返さねばなりません。 segment に渡す値はゼロまたは正の値で、bf_getsegcount スロット関数が返すセグメント数よりも必ず小さな値でなければなりません。 成功すると、セグメントのサイズを返し、 *ptrptr を そのセグメントを指すポインタ値にセットします。

Py_ssize_t (*getwritebufferproc) (PyObject *self, Py_ssize_t segment, void **ptrptr)
読み出し可能なバッファセグメントへのポインタを *ptrptr に 返し、セグメントの長さを関数の戻り値として返します。エラーによる例外の 場合には -1-1 を返さねばなりません。 オブジェクトが呼び出し専用バッファしかサポートしていない場合には TypeError を、segment が存在しないセグメントを 指している場合には SystemError を送出しなければなりません。

Py_ssize_t (*getsegcountproc) (PyObject *self, Py_ssize_t *lenp)
バッファを構成するメモリセグメントの数を返します。 lenpNULLでない場合、この関数の実装は全てのセグメント のサイズ (バイト単位) の合計値を *lenp を介して 報告しなければなりません。この関数呼び出しは失敗させられません。

Py_ssize_t (*getcharbufferproc) (PyObject *self, Py_ssize_t segment, const char **ptrptr)
セグメント segment のメモリバッファを ptrptr に入れ、 そのサイズを返します。エラーのときに -1 を返します。

ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。