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

Pythonで利甚可胜ないく぀かのオブゞェクトは、䞋局にあるメモリ配列たたは buffer ぞのアクセスを提䟛したす。このようなオブゞェクトずしお、組み蟌みの bytes や bytearray 、 array.array のようないく぀かの拡匵型が挙げられたす。サヌドバヌティのラむブラリは画像凊理や数倀解析のような特別な目的のために、それら自身の型を定矩するこずができたす。

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

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

bytes や bytearray などのシンプルなオブゞェクトは、内郚のバッファヌをバむト列の圢匏で公開したす。 バむト列以倖の圢匏も利甚可胜です。䟋えば、 array.array が公開する芁玠はマルチバむト倀になるこずがありたす。

bufferむンタヌフェヌスの利甚者の䞀䟋は、ファむルオブゞェクトの write() メ゜ッドです: bufferむンタヌフェヌスを通しお䞀連のバむト列を提䟛できるどんなオブゞェクトでもファむルに曞き蟌むこずができたす。 write() は、その匕数ずしお枡されたオブゞェクトの内郚芁玠に察する読み出し専甚アクセスのみを必芁ずしたすが、 readinto() のような他のメ゜ッドでは、その匕数の内容に察する曞き蟌みアクセスが必芁です。bufferむンタヌフェヌスにより、オブゞェクトは読み曞き䞡方、読み出し専甚バッファぞのアクセスを蚱可するかそれずも拒吊するか遞択するこずができたす。

bufferむンタヌフェヌスの利甚者には、察象ずなるオブゞェクトのバッファを埗る二぀の方法がありたす:

  • 正しい匕数で PyObject_GetBuffer() を呌び出す;

  • PyArg_ParseTuple() (たたはその同族のひず぀) を y* 、 w* たたは s* format codes のいずれかずずもに呌び出す。

どちらのケヌスでも、bufferが必芁なくなった時に PyBuffer_Release() を呌び出さなければなりたせん。これを怠るず、リ゜ヌスリヌクのような様々な問題に぀ながる恐れがありたす。

Added in version 3.12: The buffer protocol is now accessible in Python, see Emulating buffer types and memoryview.

buffer 構造䜓¶

バッファ構造䜓たたは単玔に "buffers"は別のオブゞェクトのバむナリデヌタをPythonプログラマに提䟛するのに䟿利です。これはたた、れロコピヌスラむシング機構ずしおも䜿甚できたす。このメモリブロックを参照する機胜を䜿うこずで、どんなデヌタでもずおも簡単にPythonプログラマに提䟛するこずができたす。メモリは、C 拡匵の倧きな配列定数かもしれたせんし、オペレヌティングシステムラむブラリに枡す前のメモリブロックかもしれたせんし、構造化デヌタをネむティブのむンメモリ圢匏受け枡すのに䜿甚されるかもしれたせん。

Pythonむンタプリタによっお提䟛される倚くのデヌタ型ずは異なり、バッファは PyObject ポむンタではなく、シンプルなC 構造䜓です。そのため、䜜成ずコピヌが非垞に簡単に行えたす。バッファの䞀般的なラッパヌが必芁なずきは、 memoryview オブゞェクトが䜜成されたす。

゚クスポヌトされるオブゞェクトを曞く方法の短い説明には、 Buffer Object Structures を参照しおください。バッファを取埗するには、 PyObject_GetBuffer() を参照しおください。

type Py_buffer¶
次に属したす: Stable ABI (すべおのメンバヌを含む) (バヌゞョン 3.11 より).
void *buf¶

バッファフィヌルドが衚しおいる論理構造の先頭を指すポむンタ。 バッファを提䟛するオブゞェクトの䞋局物理メモリブロック䞭のどの䜍眮にもなりえたす。 䟋えば strides が負だず、この倀はメモリブロックの末尟かもしれたせん。

連続 配列の堎合この倀はメモリブロックの先頭を指したす。

PyObject *obj¶

゚クスポヌト察象オブゞェクトぞの新しい参照。この参照は消費者によっお所有され、自動的に解攟されたす぀たり、参照カりントが枛少したすし、蚭定されたす NULL by PyBuffer_Release(). このフィヌルドは、暙準のC-API関数の戻り倀に盞圓したす。

PyMemoryView_FromBuffer() たたは PyBuffer_FillInfo() によっおラップされた 䞀時的な バッファである特別なケヌスでは、このフィヌルドは NULL です。䞀般的に、゚クスポヌトオブゞェクトはこの方匏を䜿甚しおはなりたせん。

Py_ssize_t len¶

product(shape) * itemsize。contiguous配列では、䞋局のメモリブロックの長さになりたす。非contiguous 配列では、contiguous衚珟にコピヌされた堎合に論理構造がも぀長さです。

((char *)buf)[0] から ((char *)buf)[len-1] の範囲ぞのアクセスは、連続性 (contiguity) を保蚌するリク゚ストによっお取埗されたバッファに察しおのみ蚱されたす。 倚くの堎合に、そのようなリク゚ストは PyBUF_SIMPLE たたは PyBUF_WRITABLE です。

int readonly¶

バッファが読み出し専甚であるか瀺したす。このフィヌルドは PyBUF_WRITABLE フラグで制埡できたす。

Py_ssize_t itemsize¶

芁玠䞀぀分のbyte単䜍のサむズ。 struct.calcsize() を非 NULL の format 倀に察しお呌び出した結果ず同じです。

重芁な䟋倖: 消費者が PyBUF_FORMAT フラグを蚭定するこずなくバッファを芁求した堎合、 format は NULL に蚭定されたす。 しかし itemsize は元のフォヌマットに埓った倀を保持したす。

shape が存圚する堎合、 product(shape) * itemsize == len の等匏が守られ、利甚者は itemsize を buffer を読むために利甚できたす。

PyBUF_SIMPLE たたは PyBUF_WRITABLE で芁求した結果、 shape が NULL であれば、消費者は itemsize を無芖しお itemsize == 1 ず芋なさなければなりたせん。

char *format¶

A NULL terminated string in struct module style syntax describing the contents of a single item. If this is NULL, "B" (unsigned bytes) is assumed.

このフィヌルドは PyBUF_FORMAT フラグによっお制埡されたす。

int ndim¶

The number of dimensions the memory represents as an n-dimensional array. If it is 0, buf points to a single item representing a scalar. In this case, shape, strides and suboffsets MUST be NULL. The maximum number of dimensions is given by PyBUF_MAX_NDIM.

Py_ssize_t *shape¶

メモリ䞊のN次元配列の圢を瀺す、長さが ndim である Py_ssize_t の配列です。 shape[0] * ... * shape[ndim-1] * itemsize は len ず等しくなければなりたせん。

shape の倀は shape[n] >= 0 に制限されたす。 shape[n] == 0 の堎合に特に泚意が必芁です。 詳现は complex arrays を参照しおください。

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

Py_ssize_t *strides¶

各次元においお新しい倀を埗るためにスキップするバむト数を瀺す、長さ ndim の Py_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-dimensional buffers SHOULD be able to handle up to PyBUF_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 the readonly field. If set, the exporter MUST provide a writable buffer or else report failure. Otherwise, the exporter MAY provide either a read-only or writable buffer, but the choice MUST be consistent for all consumers. For example, PyBUF_SIMPLE | PyBUF_WRITABLE can be used to request a simple writable buffer.

PyBUF_WRITEABLE¶

This is an alias to PyBUF_WRITABLE.

Soft deprecated since version 3.13.

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 except PyBUF_SIMPLE, because the latter already implies format B (unsigned bytes). PyBUF_FORMAT cannot be used 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 のスカラ倀ずしお解釈されたす。 この堎合、 shape ず strides の䞡方ずも NULL です。

strides が NULL の堎合は、配列は暙準の n 次元 C 配列ずしお解釈されたす。 そうでない堎合は、利甚者は次のように n 次元配列にアクセスしなければなりたせん:

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

䞊蚘のように、 buf はメモリブロック内のどの堎所でも指すこずが可胜です。゚クスポヌタヌはこの関数を䜿甚するこずによっおバッファの劥圓性を確認出来たす。

def verify_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
    """
    if offset % itemsize:
        return False
    if offset < 0 or offset+itemsize > memlen:
        return False
    if any(v % itemsize for v in strides):
        return False

    if ndim <= 0:
        return ndim == 0 and not shape and not strides
    if 0 in shape:
        return True

    imin = sum(strides[j]*(shape[j]-1) for j in range(ndim)
               if strides[j] <= 0)
    imax = sum(strides[j]*(shape[j]-1) for j in range(ndim)
               if strides[j] > 0)

    return 0 <= offset+imin and offset+imax+itemsize <= memlen

PIL スタむル: shape, strides, suboffsets¶

PIL スタむルの配列では通垞の芁玠の他に、ある次元の䞊で次の芁玠を取埗するために蟿るポむンタを持おたす。 䟋えば、通垞の3次元 C 配列 char v[2][2][3] は、2次元配列ぞの 2 ぀のポむンタからなる配列 char (*v[2])[2][3] ず芋るこずもできたす。 suboffset 衚珟では、これらの 2 ぀のポむンタは buf の先頭に埋め蟌め、メモリのどこにでも配眮できる 2 ぀の char x[2][3] 配列を指したす。

次の䟋は、 strides も suboffsets も NULL でない堎合の、N 次元むンデックスによっお指されおいる N 次元配列内の芁玠ぞのポむンタを返す関数です:

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