# buffer オブジェクトと memoryview オブジェクト

C で実装された Python オブジェクトは、"バッファインタフェース (buffer interface)" と呼ばれる一連の関数を公開していることがあります。これらの関数は、あるオブジェクトのデータを生 (raw) のバイト列形式で公開するために使います。このオブジェクトの使い手は、バッファインタフェースを使うことで、オブジェクトをあらかじめコピーしておく必要なしに、オブジェクトのデータに直接アクセスできます。

バッファインタフェースをサポートするオブジェクトの例として、文字列型とアレイ (array) 型の二つがあります。文字列オブジェクトは、その内容をバッファインタフェースのバイト指向の形式で公開しています。アレイはその内容を旧スタイルバッファインターフェイス経由でしか公開できません。この制限は `memoryview` オブジェクトをアレイから構築出来る Python 3 には適用されません。アレイの要素は複数バイトの値になりえます。

バッファインタフェースの使い手の一例として、ファイルオブジェクトの `write()` メソッドがあります。バッファインタフェースを介してバイト列を公開しているオブジェクトは全て、ファイルへの書き出しができます。オブジェクトのバッファインタフェースを操作し、対象となるオブジェクトからデータを返させる `PyArg_ParseTuple()` には数多くのデータ書式化コードがあります。

バージョン 1.6 から、Python は Python レベルのバッファオブジェクトと、 C 言語レベルのバッファ API を提供しており、任意のビルトイン型やユーザー定義型はその文字列表現を公開することができます。しかし、両方共、幾つかの欠点のために廃止予定扱いされていて、 Python 3 では公式に削除され、新しい C 言語レベルのバッファ API と新しい Python レベルの `memoryview` という名前のオブジェクトに置き換えられています。

新しいバッファ API は Python 2.6 に逆移植されており、 `memoryviews` オブジェクトは Python 2.7 に逆移植されています。古いバージョンとの互換性が必要なければ、古いAPIの代わりにこれらを使うことをおすすめします。

## 新スタイル Py_buffer 構造体

`Py_buffer`
  void *`buf`

    オブジェクトのメモリの開始位置へのポインタ

  Py_ssize_t `len`

    メモリのトータルサイズ [byte]

  int `readonly`

    バッファが読み込み専用かどうかを示す

  const char *`format`

    バッファを通してアクセスできる要素の形式を指定する、 `struct` モジュールスタイル文法の、 NULL 終端文字列。このポインタの値が NULL なら、 `"B"` (符号無しバイト) として扱われます。

  int `ndim`

    メモリが多次元配列を表している時の次元数。 `0` の場合、 `strides` と `suboffsets` は NULL でなければなりません。

  Py_ssize_t *`shape`

    メモリが多次元配列を表しているとき、その形を示す長さ `ndim` の `Py_ssize_t` の配列。 `((*shape)[0] * ... * (*shape)[ndims-1])*itemsize` は `len` と等しくなければならないことに気をつけてください。

  Py_ssize_t *`strides`

    各次元で次の要素を得るためにスキップするバイト数を示す、長さ `ndim` の `Py_ssize_t` の配列。

  Py_ssize_t *`suboffsets`

    長さ `ndim` の `Py_ssize_t` の配列。 suboffset の各数値が 0 以上であるとき、その次元に格納されているのはポインタで、 suboffset の値はそのポインタの参照を解決するときに何バイトのオフセットを足すかを示しています。 suboffset に負の数が格納されているときは、参照解決が不要であること (連続したメモリブロック内に直接配置されていること)を意味しています。

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

    次の例は、 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;
         }

  Py_ssize_t `itemsize`

    これは共有メモリ上の各要素のbyte単位のサイズを格納する変数です。これは `PyBuffer_SizeFromFormat()` を使って計算できる値なので技術的には不要なのですが、バッファを提供する側はフォーマット文字列を解析しなくてもこの情報を知っているでしょうし、バッファを受け取る側にとっては正しく解釈するのに必要な情報です。なので、要素サイズを格納するほうが便利ですし高速です。

  void *`internal`

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

## バッファ関連関数

int `PyObject_CheckBuffer`(PyObject *obj)

  obj がバッファインタフェースをサポートしている場合に `1` を、それ以外の場合に `0` を返します。

int `PyObject_GetBuffer`(PyObject *obj, Py_buffer *view, int flags)

  obj を `Py_buffer` view へエクスポートします。これらの引数は NULL であってはなりません。 flag 引数は呼び出し側がどんなバッファを扱おうとしているのか、バッファ提供側がどんなバッファを返すことが許されているのかを示す、ビットフィールドです。バッファインタフェースは複雑なメモリ共有を可能にしていますが、呼び出し元はすべての複雑なバッファを扱えるとは限らず、バッファ提供側がシンプルなビューを提供できるならそれを利用したいとかもしれません。

  バッファ提供側はすべての方法でメモリを共有できるとは限らず、呼び出し側に何かが不可能であることを伝えるためにエラーを発生させる必要があるかもしれません。その場合のエラーは、もしその問題を実際に引き起こしているのが別のエラーだったとしても、 `BufferError` でなければなりません。バッファ提供側は flag の情報を使って `Py_buffer` 構造体のどのフィールドへの非デフォルト値の設定を省略したり、要求されたシンプルな view を提供できない場合はエラーを発生させたりすることができます。

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

  次のテーブルは、 flags 引数が取りうる値です。

  Flag | 説明
  --- | ---
  `PyBUF_SIMPLE` | これはデフォルトの flag の状態です。結果のバッファは書き込み可能かもしれませんし、不可能かもしれません。データのフォーマットは unsigned byte とします。これは "スタンドアロン" のフラグ定数です。他の定数と '|' を取る必要はありません。提供側はこのような連続したバイト列のバッファを提供できない場合に、エラーを発生させるかもしれません。
  `PyBUF_WRITABLE` | 結果のバッファは書込み可能でなければなりません。書き込み不可能な場合はエラーを発生させます。
  `PyBUF_STRIDES` | この値は `PyBUF_ND` を含みます。バッファは strides 情報を提供しなければなりません。 (言い換えると、 strides は NULL であってはいけません。) このフラグは、呼び出し元が、要素間に隙間のある不連続な配列を扱えるときに使われます。 strides を扱うことは、自動的に shape も扱えることを要求されます。提供側は stride 形式のバッファを提供できないとき(例えば、 suboffset が必要な場合)はエラーを発生させます。
  `PyBUF_ND` | バッファは shape 情報を提供しなければなりません。メモリは C スタイルの並び (最後の次元が一番高速) だと仮定されます。提供側はこの種類の連続バッファを提供できない場合はエラーを発生させます。このフラグが指定されていな場合は shape は NULL になります。
  `PyBUF_C_CONTIGUOUS` `PyBUF_F_CONTIGUOUS` `PyBUF_ANY_CONTIGUOUS` | これらのフラグは、返されるバッファの並びを指定します。それぞれ、C並び(最後の次元が一番高速)、Fortran並び(最初の次元が一番高速), そのどちらでも、を意味します。これらのフラグは `PyBUF_STRIDES` を含んでおり、 strides 情報が正しく格納されていることを保証します。
  `PyBUF_INDIRECT` | このフラグは、返されるバッファが suboffsets 情報を含んでいることを示します。(suboffsets が必要無いときは NULL でもかまいません。) このフラグは、バッファ利用側が suboffsets を使って参照されている間接配列を扱えるときに利用されます。このフラグは `PyBUF_STRIDES` を含みます。
  `PyBUF_FORMAT` | 返されるバッファは正しい format 情報を持っていなければなりません。このフラグは、バッファ利用側が実際に格納されているデータの '種類' をチェックするときに利用します。バッファ提供側は、要求された場合は常にこの情報を提供できるべきです。 format が明示的に要求されていない場合は format は NULL (`'B'`, unsigned byte を意味する)であるべきです。
  `PyBUF_STRIDED` | `(PyBUF_STRIDES | PyBUF_WRITABLE)` と同じ
  `PyBUF_STRIDED_RO` | `(PyBUF_STRIDES)` と同じ
  `PyBUF_RECORDS` | `(PyBUF_STRIDES | PyBUF_FORMAT | PyBUF_WRITABLE)` と同じ
  `PyBUF_RECORDS_RO` | `(PyBUF_STRIDES | PyBUF_FORMAT)` と同じ
  `PyBUF_FULL` | `(PyBUF_INDIRECT | PyBUF_FORMAT | PyBUF_WRITABLE)` と同じ
  `PyBUF_FULL_RO` | `(PyBUF_INDIRECT | PyBUF_FORMAT)` と同じ
  `PyBUF_CONTIG` | `(PyBUF_ND | PyBUF_WRITABLE)` と同じ
  `PyBUF_CONTIG_RO` | `(PyBUF_ND)` と同じ

void `PyBuffer_Release`(Py_buffer *view)

  view バッファを解放します。バッファが利用されなくなったときに、そのメモリを解放できるようにこの関数を呼び出すべきです。

Py_ssize_t `PyBuffer_SizeFromFormat`(const char *)

  `itemsize` の値を `format` から計算して返します。

int `PyBuffer_IsContiguous`(Py_buffer *view, char fortran)

  view で定義されているメモリが、 C スタイル (fortran == `'C'`) のときか、 Fortran スタイル (fortran == `'F'`) のときか、そのいずれか (fortran == `'A'`) であれば `1` を返します。それ以外の場合は `0` を返します。

void `PyBuffer_FillContiguousStrides`(int ndims, Py_ssize_t *shape, Py_ssize_t *strides, int itemsize, char fortran)

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

int `PyBuffer_FillInfo`(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, int readonly, int infoflags)

  バッファ提供側が与えられた長さの "unsigned bytes" の連続した1つのメモリブロックしか提供できないものとして、 view バッファ情報構造体を正しく埋める。成功したら `0` を、エラー時には (例外を発生させつつ) `-1` を返す。

## memoryview オブジェクト

バージョン 2.7 で追加.

`memoryview` オブジェクトは、新しい、他のオブジェクトと同じように扱える Python オブジェクトの形をした C言語レベルのバッファへのインタフェースです。

PyObject *`PyMemoryView_FromObject`(PyObject *obj)

  新しいバッファインタフェースを定義しているオブジェクトから memoryview オブジェクトを作ります。

PyObject *`PyMemoryView_FromBuffer`(Py_buffer *view)

  buffer-info 構造体 view をラップする memoryview オブジェクトを作ります。作られた memoryview オブジェクトはバッファを所有することになるので、 view を解放してはいけません。このバッファは memoryview オブジェクトが削除されるときに解放されます。

PyObject *`PyMemoryView_GetContiguous`(PyObject *obj, int buffertype, char order)

  buffer インタフェースを定義しているオブジェクトから ('C' か 'F'ortran の order で) 連続したメモリチャンクへの memoryview オブジェクトを作ります。メモリが連続している場合、 memoryview オブジェクトは元のメモリを参照します。それ以外の場合、メモリはコピーされて、 memoryview オブジェクトは新しい bytes オブジェクトを参照します。

int `PyMemoryView_Check`(PyObject *obj)

  obj が memoryview オブジェクトの場合に真を返します。現在のところ、 `memoryview` のサブクラスの作成は許可されていません。

Py_buffer *`PyMemoryView_GET_BUFFER`(PyObject *obj)

  与えられたオブジェクトにラップされた buffer-info 構造体へのポインタを返します。オブジェクトは memoryview インスタンスで なければなりません 。このマクロはオブジェクトの型をチェックしないので、呼び出し側で保証しなければクラッシュする可能性があります。

## 旧スタイルバッファオブジェクト

古いバッファインタフェースに関するより詳しい情報は、 "バッファオブジェクト構造体" 節 ( バッファオブジェクト構造体 (buffer object structure) 節) の、 `PyBufferProcs` の説明のところにあります。

"バッファオブジェクト" はヘッダファイル `bufferobject.h` の中で定義されています (このファイルは `Python.h` がインクルードしています)。バッファオブジェクトは、 Python プログラミングのレベルからは文字列オブジェクトと非常によく似ているように見えます: スライス、インデックス指定、結合、その他標準の文字列操作をサポートしています。しかし、バッファオブジェクトのデータは二つのデータソース: 何らかのメモリブロックか、バッファインタフェースを公開している別のオブジェクト、のいずれかに由来しています。

バッファオブジェクトは、他のオブジェクトのバッファインタフェースから Python プログラマにデータを公開する方法として便利です。バッファオブジェクトはゼロコピーなスライス機構 (zero-copy slicing mechanism) としても使われます。ブロックメモリを参照するというバッファオブジェクトの機能を使うことで、任意のデータをきわめて簡単に Python プログラマに公開できます。メモリブロックは巨大でもかまいませんし、C 拡張モジュール内の定数配列でもかまいません。また、オペレーティングシステムライブラリ側に渡す前の、操作用の生のブロックメモリでもかまいませんし、構造化されたデータをネイティブのメモリ配置形式でやりとりするためにも使えます。

`PyBufferObject`

  この `PyObject` のサブタイプはバッファオブジェクトを表現します。

PyTypeObject `PyBuffer_Type`

  Python バッファ型 (buffer type) を表現する `PyTypeObject` です; Python レイヤにおける `buffer` や `types.BufferType` と同じオブジェクトです。

int `Py_END_OF_BUFFER`

  この定数は、 `PyBuffer_FromObject()` や `PyBuffer_FromReadWriteObject()` に size パラメタとして渡します。このパラメタを渡すと、 `PyBufferObject` は指定された offset からバッファの終わりまでを base オブジェクトとして参照します。このパラメタを使うことで、関数の呼び出し側が base オブジェクトのサイズを調べる必要がなくなります。

int `PyBuffer_Check`(PyObject *p)

  引数が `PyBuffer_Type` 型のときに真を返します。

PyObject* `PyBuffer_FromObject`(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
  Return value: New reference.

  新たな読み出し専用バッファオブジェクトを返します。 base が読み出し専用バッファに必要なバッファプロトコルをサポートしていない場合や、厳密に一つのバッファセグメントを提供していない場合には `TypeError` を送出し、 offset がゼロ以下の場合には `ValueError` を送出します。バッファオブジェクトは base オブジェクトに対する参照を保持し、バッファオブジェクトの内容は base オブジェクトの offset から size バイトのバッファインタフェースへの参照になります。 size が `Py_END_OF_BUFFER` の場合、新たに作成するバッファオブジェクトの内容は base から公開されているバッファの末尾までにわたります。

  バージョン 2.5 で変更: この関数は以前は offset, size の型に `int` を利用していました。この変更により、 64bit システムを正しくサポートするには修正が必要になります。

PyObject* `PyBuffer_FromReadWriteObject`(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
  Return value: New reference.

  新たな書き込み可能バッファオブジェクトを返します。パラメタおよび例外は `PyBuffer_FromObject()` と同じです。 base オブジェクトが書き込み可能バッファに必要なバッファプロトコルを公開していない場合、 `TypeError` を送出します。

  バージョン 2.5 で変更: この関数は以前は offset, size の型に `int` を利用していました。この変更により、 64bit システムを正しくサポートするには修正が必要になります。

PyObject* `PyBuffer_FromMemory`(void *ptr, Py_ssize_t size)
  Return value: New reference.

  メモリ上の指定された場所から指定されたサイズのデータを読み出せる、新たな読み出し専用バッファオブジェクトを返します。この関数が返すバッファオブジェクトが存続する間、 ptr で与えられたメモリバッファがデアロケートされないようにするのは呼び出し側の責任です。 size がゼロ以下の場合には `ValueError` を送出します。 size には `Py_END_OF_BUFFER` を指定しては いけません ; 指定すると、 `ValueError` を送出します。

  バージョン 2.5 で変更: この関数は以前は size の型に `int` を利用していました。この変更により、 64bit システムを正しくサポートするには修正が必要になります。

PyObject* `PyBuffer_FromReadWriteMemory`(void *ptr, Py_ssize_t size)
  Return value: New reference.

  `PyBuffer_FromMemory()` に似ていますが、書き込み可能なバッファを返します。

  バージョン 2.5 で変更: この関数は以前は size の型に `int` を利用していました。この変更により、 64bit システムを正しくサポートするには修正が必要になります。

PyObject* `PyBuffer_New`(Py_ssize_t size)
  Return value: New reference.

  size バイトのメモリバッファを独自に維持する新たな書き込み可能バッファオブジェクトを返します。 size がゼロまたは正の値でない場合、 `ValueError` を送出します。( `PyObject_AsWriteBuffer()` が返すような) メモリバッファは特に整列されていないので注意して下さい。

  バージョン 2.5 で変更: この関数は以前は size の型に `int` を利用していました。この変更により、 64bit システムを正しくサポートするには修正が必要になります。