バッファプロトコル (buffer Protocol)

Pythonで利用可能ないくつかのオブジェクトは、下層にあるメモリ配列またはbuffer へのアクセスを提供します。このようなオブジェクトとして、組み込みのbytesbytearrayarray.array のようないくつかの拡張型が挙げられます。サードバーティのライブラリは画像処理や数値解析のような特別な目的のために、それら自身の型を定義することができます。

それぞれの型はそれ自身のセマンティクスを持ちますが、おそらく大きなメモリバッファからなるという共通の特徴を共有します。いくつかの状況では仲介するコピーを行うことなく直接バッファにアクセスすることが望まれます。

Python provides such a facility at the C and Python level in the form of thebuffer protocol. This protocol has two sides:

bytesbytearray などのシンプルなオブジェクトは、内部のバッファーをバイト列の形式で公開します。バイト列以外の形式も利用可能です。例えば、array.array が公開する要素はマルチバイト値になることがあります。

bufferインターフェースの利用者の一例は、ファイルオブジェクトのwrite() メソッドです: bufferインターフェースを通して一連のバイト列を提供できるどんなオブジェクトでもファイルに書き込むことができます。write() は、その引数として渡されたオブジェクトの内部要素に対する読み出し専用アクセスのみを必要としますが、readinto() のような他のメソッドでは、その引数の内容に対する書き込みアクセスが必要です。bufferインターフェースにより、オブジェクトは読み書き両方、読み出し専用バッファへのアクセスを許可するかそれとも拒否するか選択することができます。

bufferインターフェースの利用者には、対象となるオブジェクトのバッファを得る二つの方法があります:

どちらのケースでも、bufferが必要なくなった時にPyBuffer_Release() を呼び出さなければなりません。これを怠ると、リソースリークのような様々な問題につながる恐れがあります。

Added in version 3.12:The buffer protocol is now accessible in Python, seeEmulating buffer types andmemoryview.

buffer 構造体

バッファ構造体(または単純に "buffers")は別のオブジェクトのバイナリデータをPythonプログラマに提供するのに便利です。これはまた、ゼロコピースライシング機構としても使用できます。このメモリブロックを参照する機能を使うことで、どんなデータでもとても簡単にPythonプログラマに提供することができます。メモリは、C 拡張の大きな配列定数かもしれませんし、オペレーティングシステムライブラリに渡す前のメモリブロックかもしれませんし、構造化データをネイティブのインメモリ形式受け渡すのに使用されるかもしれません。

Pythonインタプリタによって提供される多くのデータ型とは異なり、バッファはPyObject ポインタではなく、シンプルなC 構造体です。そのため、作成とコピーが非常に簡単に行えます。バッファの一般的なラッパーが必要なときは、memoryview オブジェクトが作成されます。

エクスポートされるオブジェクトを書く方法の短い説明には、Buffer Object Structures を参照してください。バッファを取得するには、PyObject_GetBuffer() を参照してください。

typePy_buffer
次に属します:Stable ABI (すべてのメンバーを含む) (バージョン 3.11 より).
void*buf

バッファフィールドが表している論理構造の先頭を指すポインタ。バッファを提供するオブジェクトの下層物理メモリブロック中のどの位置にもなりえます。例えばstrides が負だと、この値はメモリブロックの末尾かもしれません。

連続 配列の場合この値はメモリブロックの先頭を指します。

PyObject*obj

エクスポート対象オブジェクトへの新しい参照。この参照は消費者によって所有され、自動的に解放されます(つまり、参照カウントが減少します)し、設定されますNULL byPyBuffer_Release(). このフィールドは、標準のC-API関数の戻り値に相当します。

PyMemoryView_FromBuffer() またはPyBuffer_FillInfo() によってラップされた一時的な バッファである特別なケースでは、このフィールドはNULL です。一般的に、エクスポートオブジェクトはこの方式を使用してはなりません。

Py_ssize_tlen

product(shape)*itemsize。contiguous配列では、下層のメモリブロックの長さになります。非contiguous 配列では、contiguous表現にコピーされた場合に論理構造がもつ長さです。

((char*)buf)[0] から((char*)buf)[len-1] の範囲へのアクセスは、連続性 (contiguity) を保証するリクエストによって取得されたバッファに対してのみ許されます。多くの場合に、そのようなリクエストはPyBUF_SIMPLE またはPyBUF_WRITABLE です。

intreadonly

バッファが読み出し専用であるか示します。このフィールドはPyBUF_WRITABLE フラグで制御できます。

Py_ssize_titemsize

要素一つ分のbyte単位のサイズ。struct.calcsize() を非NULLformat 値に対して呼び出した結果と同じです。

重要な例外: 消費者がPyBUF_FORMAT フラグを設定することなくバッファを要求した場合、formatNULL に設定されます。しかしitemsize は元のフォーマットに従った値を保持します。

shape が存在する場合、product(shape)*itemsize==len の等式が守られ、利用者はitemsize を buffer を読むために利用できます。

PyBUF_SIMPLE またはPyBUF_WRITABLE で要求した結果、shapeNULL であれば、消費者はitemsize を無視してitemsize==1 と見なさなければなりません。

char*format

ANULL terminated string instruct module style syntax describingthe contents of a single item. If this isNULL,"B" (unsigned bytes)is assumed.

このフィールドはPyBUF_FORMAT フラグによって制御されます。

intndim

The number of dimensions the memory represents as an n-dimensional array.If it is0,buf points to a single item representinga scalar. In this case,shape,stridesandsuboffsets MUST beNULL.The maximum number of dimensions is given byPyBUF_MAX_NDIM.

Py_ssize_t*shape

メモリ上のN次元配列の形を示す、長さがndim であるPy_ssize_t の配列です。shape[0]*...*shape[ndim-1]*itemsizelen と等しくなければなりません。

shape の値はshape[n]>=0 に制限されます。shape[n]==0 の場合に特に注意が必要です。詳細はcomplex arrays を参照してください。

shepe (形状) 配列は利用者からは読み出し専用です。

Py_ssize_t*strides

各次元において新しい値を得るためにスキップするバイト数を示す、長さndimPy_ssize_t の配列。

ストライド値は、任意の整数を指定できます。規定の配列では、ストライドは通常でいけば有効です。しかし利用者は、strides[n]<=0 のケースを処理することができる必要があります。詳細についてはcomplex arrays を参照してください。

消費者にとって、この strides 配列は読み出し専用です。

Py_ssize_t*suboffsets

Py_ssize_t 型の要素を持つ長さndim の配列。suboffsets[n]>=0 の場合は、 n 番目の次元に沿って保存されている値はポインタで、 suboffset 値は各ポインタの参照を解決した後に何バイト加えればいいかを示しています。suboffset の値が負の数の場合は、ポインタの参照解決は不要 (連続したメモリブロック内に直接配置されいる) ということになります。

全ての suboffset が負数の場合 (つまり参照解決が不要) な場合、このフィールドはNULL (デフォルト値) でなければなりません。

この種の配列表現は Python Imaging Library (PIL) で使われています。このような配列で要素にアクセスする方法についてさらに詳しことはcomplex arrays を参照してください。

消費者にとって、suboffsets 配列は読み出し専用です。

void*internal

バッファを提供する側のオブジェクトが内部的に利用するための変数です。例えば、提供側はこの変数に整数型をキャストして、shape, strides, suboffsets といった配列をバッファを開放するときに同時に解放するべきかどうかを管理するフラグに使うことができるでしょう。バッファを受け取る側は、この値を決して変更してはなりません。

Constants:

PyBUF_MAX_NDIM
次に属します:Stable ABI (バージョン 3.11 より).

The maximum number of dimensions the memory represents.Exporters MUST respect this limit, consumers of multi-dimensionalbuffers SHOULD be able to handle up toPyBUF_MAX_NDIM dimensions.Currently set to 64.

バッファリクエストのタイプ

バッファは通常、PyObject_GetBuffer() を使うことで、エクスポートするオブジェクトにバッファリクエストを送ることで得られます。メモリの論理的な構造の複雑性は多岐にわたるため、消費者はflags 引数を使って、自身が扱えるバッファの種類を指定します。

Py_buffer の全フィールドは、リクエストの種類によって曖昧さを残さずに定義されます。

リクエストに依存しないフィールド

下記のフィールドはflags の影響を受けずに、常に正しい値で設定されます。:obj,buf,len,itemsize,ndim.

readonly, format

PyBUF_WRITABLE
次に属します:Stable ABI (バージョン 3.11 より).

Controls thereadonly field. If set, the exporterMUST provide a writable buffer or else report failure. Otherwise, theexporter MAY provide either a read-only or writable buffer, but the choiceMUST be consistent for all consumers. For example,PyBUF_SIMPLE|PyBUF_WRITABLEcan be used to request a simple writable buffer.

PyBUF_WRITEABLE

This is asoft deprecated alias toPyBUF_WRITABLE.

PyBUF_FORMAT
次に属します:Stable ABI (バージョン 3.11 より).

format フィールドを制御します。もしフラグが設定されていれば、このフィールドを正しく埋めなければなりません。フラグが設定されていなければ、このフィールドをNULL に設定しなければなりません。

PyBUF_WRITABLE は、次の節に出てくるどのフラグとも | を取ってかまいません。PyBUF_SIMPLE は 0 と定義されているので、PyBUF_WRITABLE は単純な書き込み可能なバッファを要求する単独のフラグとして使えます。

PyBUF_FORMAT must be |'d to any of the flags exceptPyBUF_SIMPLE, becausethe latter already implies formatB (unsigned bytes).PyBUF_FORMAT cannot beused on its own.

shape, strides, suboffsets

このフラグは、以下で複雑性が大きい順に並べたメモリの論理的な構造を制御します。個々のフラグは、それより下に記載されたフラグのすべてのビットを含むことに注意してください。

リクエスト

shape

strides

suboffsets

PyBUF_INDIRECT
次に属します:Stable ABI (バージョン 3.11 より).

yes

yes

必要な場合

PyBUF_STRIDES
次に属します:Stable ABI (バージョン 3.11 より).

yes

yes

NULL

PyBUF_ND
次に属します:Stable ABI (バージョン 3.11 より).

yes

NULL

NULL

PyBUF_SIMPLE
次に属します:Stable ABI (バージョン 3.11 より).

NULL

NULL

NULL

隣接性のリクエスト

ストライドの情報があってもなくても、C または Fortran の連続性 が明確に要求される可能性があります。ストライド情報なしに、バッファーは C と隣接している必要があります。

リクエスト

shape

strides

suboffsets

contig

PyBUF_C_CONTIGUOUS
次に属します:Stable ABI (バージョン 3.11 より).

yes

yes

NULL

C

PyBUF_F_CONTIGUOUS
次に属します:Stable ABI (バージョン 3.11 より).

yes

yes

NULL

F

PyBUF_ANY_CONTIGUOUS
次に属します:Stable ABI (バージョン 3.11 より).

yes

yes

NULL

C か F

PyBUF_ND

yes

NULL

NULL

C

複合リクエスト

有り得る全てのリクエストの値は、前の節でのフラグの組み合わせで網羅的に定義されています。便利なように、バッファープロトコルでは頻繁に使用される組み合わせを単一のフラグとして提供してます。

次のテーブルのU は連続性が未定義であることを表します。利用者はPyBuffer_IsContiguous() を呼び出して連続性を判定する必要があるでしょう。

リクエスト

shape

strides

suboffsets

contig

readonly

format

PyBUF_FULL
次に属します:Stable ABI (バージョン 3.11 より).

yes

yes

必要な場合

U

0

yes

PyBUF_FULL_RO
次に属します:Stable ABI (バージョン 3.11 より).

yes

yes

必要な場合

U

1 か 0

yes

PyBUF_RECORDS
次に属します:Stable ABI (バージョン 3.11 より).

yes

yes

NULL

U

0

yes

PyBUF_RECORDS_RO
次に属します:Stable ABI (バージョン 3.11 より).

yes

yes

NULL

U

1 か 0

yes

PyBUF_STRIDED
次に属します:Stable ABI (バージョン 3.11 より).

yes

yes

NULL

U

0

NULL

PyBUF_STRIDED_RO
次に属します:Stable ABI (バージョン 3.11 より).

yes

yes

NULL

U

1 か 0

NULL

PyBUF_CONTIG
次に属します:Stable ABI (バージョン 3.11 より).

yes

NULL

NULL

C

0

NULL

PyBUF_CONTIG_RO
次に属します:Stable ABI (バージョン 3.11 より).

yes

NULL

NULL

C

1 か 0

NULL

複雑な配列

NumPy スタイル: shape, strides

NumPy スタイルの配列の論理的構造はitemsize,ndim,shape,strides で定義されます。

ndim==0 の場合は、buf が指すメモリの場所は、サイズがitemsize のスカラ値として解釈されます。この場合、shapestrides の両方ともNULL です。

stridesNULL の場合は、配列は標準の n 次元 C 配列として解釈されます。そうでない場合は、利用者は次のように n 次元配列にアクセスしなければなりません:

ptr=(char*)buf+indices[0]*strides[0]+...+indices[n-1]*strides[n-1];item=*((typeof(item)*)ptr);

上記のように、buf はメモリブロック内のどの場所でも指すことが可能です。エクスポーターはこの関数を使用することによってバッファの妥当性を確認出来ます。

defverify_structure(memlen,itemsize,ndim,shape,strides,offset):"""Verify that the parameters represent a valid array within       the bounds of the allocated memory:           char *mem: start of the physical memory block           memlen: length of the physical memory block           offset: (char *)buf - mem    """ifoffset%itemsize:returnFalseifoffset<0oroffset+itemsize>memlen:returnFalseifany(v%itemsizeforvinstrides):returnFalseifndim<=0:returnndim==0andnotshapeandnotstridesif0inshape:returnTrueimin=sum(strides[j]*(shape[j]-1)forjinrange(ndim)ifstrides[j]<=0)imax=sum(strides[j]*(shape[j]-1)forjinrange(ndim)ifstrides[j]>0)return0<=offset+iminandoffset+imax+itemsize<=memlen

PIL スタイル: shape, strides, suboffsets

PIL スタイルの配列では通常の要素の他に、ある次元の上で次の要素を取得するために辿るポインタを持てます。例えば、通常の3次元 C 配列charv[2][2][3] は、2次元配列への 2 つのポインタからなる配列char(*v[2])[2][3] と見ることもできます。suboffset 表現では、これらの 2 つのポインタはbuf の先頭に埋め込め、メモリのどこにでも配置できる 2 つのcharx[2][3] 配列を指します。

次の例は、 strides も suboffsets もNULL でない場合の、N 次元インデックスによって指されている N 次元配列内の要素へのポインタを返す関数です:

void*get_item_pointer(intndim,void*buf,Py_ssize_t*strides,Py_ssize_t*suboffsets,Py_ssize_t*indices){char*pointer=(char*)buf;inti;for(i=0;i<ndim;i++){pointer+=strides[i]*indices[i];if(suboffsets[i]>=0){pointer=*((char**)pointer)+suboffsets[i];}}return(void*)pointer;}

バッファ関連の関数

intPyObject_CheckBuffer(PyObject*obj)
次に属します:Stable ABI (バージョン 3.11 より).

obj がbuffer インターフェースをサポートしている場合は1 を返し、そうでない場合は0 を返します。1 を返したとしても、PyObject_GetBuffer() が成功することは保証されません。この関数は常に成功します。

intPyObject_GetBuffer(PyObject*exporter,Py_buffer*view,intflags)
次に属します:Stable ABI (バージョン 3.11 より).

exporterflags で指定された方法でview を埋めるように要求します。もし exporter が指定されたとおりにバッファを提供できない場合、BufferError を送出し、view->objNULL に設定した上で、-1 を返さなければなりません。

成功したときは、view を埋め、view->objexporter への新しい参照を設定し、0を返します。チェイン状のバッファプロバイダがリクエストを単一のオブジェクトにリダイレクトするケースでは、view->objexporter の代わりにこのオブジェクトを参照します (バッファオブジェクト構造体 を参照してください)。

malloc()free() のように、呼び出しに成功したPyObject_GetBuffer() と対になるPyBuffer_Release() の呼び出しがなけれなればなりません。従って、バッファの利用が済んだらPyBuffer_Release() が厳密に1回だけ呼び出されなければなりません。

voidPyBuffer_Release(Py_buffer*view)
次に属します:Stable ABI (バージョン 3.11 より).

Release the bufferview and release thestrong reference(i.e. decrement the reference count) to the view's supporting object,view->obj. This function MUST be called when the bufferis no longer being used, otherwise reference leaks may occur.

PyObject_GetBuffer() を通して取得していないバッファに対してこの関数を呼び出すのは間違いです。

Py_ssize_tPyBuffer_SizeFromFormat(constchar*format)
次に属します:Stable ABI (バージョン 3.11 より).

Return the implieditemsize fromformat.On error, raise an exception and return -1.

Added in version 3.9.

intPyBuffer_IsContiguous(constPy_buffer*view,charorder)
次に属します:Stable ABI (バージョン 3.11 より).

view で定義されているメモリが、 C スタイル (order =='C') のときか、 Fortran スタイル (order =='F')連続 のときか、そのいずれか (order =='A') であれば1 を返します。それ以外の場合は0 を返します。この関数は常に成功します。

void*PyBuffer_GetPointer(constPy_buffer*view,constPy_ssize_t*indices)
次に属します:Stable ABI (バージョン 3.11 より).

与えられたview 内にあるindices が指すメモリ領域を取得します。indicesview->ndim 個のインデックスからなる配列を指していなければなりません。

intPyBuffer_FromContiguous(constPy_buffer*view,constvoid*buf,Py_ssize_tlen,charfort)
次に属します:Stable ABI (バージョン 3.11 より).

連続するlen バイトをbuf からview にコピーします。fort には'C''F' を指定できます(それぞれC言語スタイルとFortranスタイルの順序を表します)。成功時には0、エラー時には-1 を返します。

intPyBuffer_ToContiguous(void*buf,constPy_buffer*src,Py_ssize_tlen,charorder)
次に属します:Stable ABI (バージョン 3.11 より).

src からlen バイトを連続表現でbuf 上にコピーします。order'C' または'F' または'A' (C スタイル順序または Fortran スタイル順序またはそれ以外) が指定できます。成功したら0 が返り、エラーなら-1 が返ります。

len !=src->len の場合、この関数は失敗します。

intPyObject_CopyData(PyObject*dest,PyObject*src)
次に属します:Stable ABI (バージョン 3.11 より).

Copy data fromsrc todest buffer. Can convert between C-style andor Fortran-style buffers.

成功したら0 が、エラー時には-1 が返されます。

voidPyBuffer_FillContiguousStrides(intndims,Py_ssize_t*shape,Py_ssize_t*strides,intitemsize,charorder)
次に属します:Stable ABI (バージョン 3.11 より).

strides 配列を、itemsize の大きさの要素がバイト単位の、shape の形をした連続な (order'C' なら C-style 、'F' なら Fortran-style の) 多次元配列として埋める。

intPyBuffer_FillInfo(Py_buffer*view,PyObject*exporter,void*buf,Py_ssize_tlen,intreadonly,intflags)
次に属します:Stable ABI (バージョン 3.11 より).

サイズがlenbufreadonly に従った書き込み可/不可の設定で公開するバッファリクエストを処理します。buf は符号無しバイトの列として解釈されます。

flags 引数はリクエストのタイプを示します。この関数は、buf が読み出し専用と指定されていて、flagsPyBUF_WRITABLE が設定されていない限り、常にフラグに指定された通りにview を埋めます。

On success, setview->obj to a new reference toexporter andreturn 0. Otherwise, raiseBufferError, setview->obj toNULL and return-1;

この関数をgetbufferproc の一部として使う場合には、exporter はエクスポートするオブジェクトに設定しなければならず、さらにflags は変更せずに渡さなければなりません。そうでない場合は、exporterNULL でなければなりません。