バッファとMemoryviewオブジェクト
Cで実装されたPythonオブジェクトは、「バッファインターフェイス」と呼ばれる関数のグループをエクスポートできます。 これらの関数は、オブジェクトがそのデータを生のバイト指向形式で公開するために使用できます。 オブジェクトのクライアントは、バッファインターフェイスを使用して、最初にオブジェクトデータをコピーしなくても、オブジェクトデータに直接アクセスできます。
バッファインターフェイスをサポートするオブジェクトの2つの例は、文字列と配列です。 文字列オブジェクトは、バッファインターフェイスのバイト指向の形式で文字の内容を公開します。 配列は、古いスタイルのバッファインターフェイスを介してのみその内容を公開できます。 この制限は、 memoryview オブジェクトを配列から構築できるPython3には適用されません。 配列要素はマルチバイト値の場合があります。
バッファインターフェイスのユーザーの例は、ファイルオブジェクトのwrite()
メソッドです。 バッファインターフェイスを介して一連のバイトをエクスポートできるオブジェクトはすべて、ファイルに書き込むことができます。 PyArg_ParseTuple()には、オブジェクトのバッファインターフェイスに対して動作し、ターゲットオブジェクトからデータを返すフォーマットコードがいくつかあります。
バージョン1.6以降、PythonはPythonレベルのバッファーオブジェクトとCレベルのバッファーAPIを提供しており、組み込み型または使用済み定義型がその特性を公開できるようになっています。 ただし、どちらもさまざまな欠点のために非推奨になり、Python 3で正式に削除され、新しいCレベルのバッファAPIと memoryview という名前の新しいPythonレベルのオブジェクトが採用されました。
新しいバッファAPIはPython2.6にバックポートされ、 memoryview オブジェクトはPython2.7にバックポートされました。 互換性の理由で使用がブロックされていない限り、古いAPIではなくそれらを使用することを強くお勧めします。
新しいスタイルのPy_buffer構造体
- type Py_buffer
- void *buf
オブジェクトのメモリの開始へのポインタ。
- int readonly
バッファが読み取り専用かどうかのインジケータ。
- int ndim
メモリが多次元配列として表す次元の数。
0
の場合、 strides および suboffsets は NULL である必要があります。
- Py_ssize_t *shape
Py_ssize_t
の長さが ndim の配列であり、多次元配列としてメモリの形状を示します。((*shape)[0] * ... * (*shape)[ndims-1])*itemsize
はlen
と等しくなければならないことに注意してください。
- Py_ssize_t *strides
Py_ssize_t
の配列は ndim の長さであり、各次元の新しい要素に到達するためにスキップするバイト数を示します。
- Py_ssize_t *suboffsets
Py_ssize_t
の配列は ndim の長さです。 これらのサブオフセット番号が0以上の場合、示された次元に沿って格納された値はポインターであり、サブオフセット値は、参照解除後にポインターに追加するバイト数を決定します。 負のサブオフセット値は、逆参照が発生してはならないことを示します(連続したメモリブロックをストライドします)。すべてのサブオフセットが負の場合(つまり、 参照解除は必要ありません)、このフィールドはNULL(デフォルト値)である必要があります。
NULL以外のストライドとサブオフセットの両方がある場合に、N次元インデックスが指すND配列内の要素へのポインターを返す関数を次に示します。
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
これは、共有メモリの各要素のアイテムサイズ(バイト単位)のストレージです。 PyBuffer_SizeFromFormat()を使用して取得できるため、技術的には不要ですが、エクスポーターはフォーマット文字列を解析せずにこの情報を知っている可能性があり、ストライドを適切に解釈するにはアイテムサイズを知る必要があります。 したがって、それを保存することはより便利でより速くなります。
- void *internal
これは、エクスポートするオブジェクトが内部で使用するためのものです。 たとえば、これはエクスポータによって整数として再キャストされ、バッファが解放されたときにシェイプ、ストライド、およびサブオフセット配列を解放する必要があるかどうかに関するフラグを格納するために使用される場合があります。 消費者はこの値を決して変更してはなりません。
- void *buf
MemoryViewオブジェクト
バージョン2.7の新機能。
memoryview オブジェクトは、新しいCレベルのバッファインターフェイスをPythonオブジェクトとして公開し、他のオブジェクトと同じように渡すことができます。
- 新しいバッファインターフェイスを定義するオブジェクトからmemoryviewオブジェクトを作成します。
- 指定されたbuffer-info構造 view をラップするmemoryviewオブジェクトを作成します。 次に、memoryviewオブジェクトがバッファを所有します。つまり、自分でバッファを解放しようとしないでください。memoryviewオブジェクトの割り当て解除時に解放されます。
- バッファインターフェイスを定義するオブジェクトから、メモリの連続したチャンク( 'C'または 'F'ortran order )にmemoryviewオブジェクトを作成します。 メモリが連続している場合、memoryviewオブジェクトは元のメモリを指します。 それ以外の場合はコピーが作成され、memoryviewは新しいbytesオブジェクトを指します。
- int PyMemoryView_Check(PyObject *obj)
- オブジェクト obj がmemoryviewオブジェクトの場合はtrueを返します。 現在、 memoryview のサブクラスを作成することは許可されていません。
- 指定されたオブジェクトによってラップされたbuffer-info構造へのポインタを返します。 オブジェクトはmemoryviewインスタンスである必要があります。 このマクロはそのタイプをチェックしません。自分でチェックする必要があります。そうしないと、クラッシュする危険があります。
古いスタイルのバッファオブジェクト
古いバッファインターフェイスの詳細については、バッファオブジェクト構造のセクションの PyBufferProcs の説明を参照してください。
「バッファオブジェクト」は、bufferobject.h
ヘッダー(Python.h
に含まれています)で定義されています。 これらのオブジェクトは、Pythonプログラミングレベルの文字列オブジェクトと非常によく似ています。スライス、インデックス作成、連結、およびその他の標準的な文字列操作をサポートしています。 ただし、それらのデータは、メモリのブロックから、またはバッファインターフェイスをエクスポートする別のオブジェクトからの2つのソースのいずれかから取得できます。
バッファオブジェクトは、別のオブジェクトのバッファインターフェイスからPythonプログラマにデータを公開する方法として役立ちます。 また、ゼロコピーのスライスメカニズムとしても使用できます。 メモリのブロックを参照する機能を使用すると、Pythonプログラマーに任意のデータを非常に簡単に公開できます。 メモリは、C拡張機能の大きな定数配列、オペレーティングシステムライブラリに渡す前の操作用の生のメモリブロック、またはネイティブのメモリ内形式で構造化データを渡すために使用できます。 。
- type PyBufferObject
- PyObject のこのサブタイプは、バッファーオブジェクトを表します。
- PyTypeObject PyBuffer_Type
- Pythonバッファタイプを表す PyTypeObject のインスタンス。 Pythonレイヤーの
buffer
およびtypes.BufferType
と同じオブジェクトです。 .
- int Py_END_OF_BUFFER
- この定数は、 size パラメーターとして PyBuffer_FromObject()または PyBuffer_FromReadWriteObject()に渡すことができます。 これは、新しい PyBufferObject が、指定された offset からエクスポートされたバッファーの終わりまでの base オブジェクトを参照する必要があることを示しています。 これを使用すると、呼び出し元は base オブジェクトにその長さを照会することを回避できます。
- int PyBuffer_Check(PyObject *p)
- 引数の型が PyBuffer_Type の場合、trueを返します。
- PyObject *PyBuffer_FromObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
新しい読み取り専用バッファオブジェクトを返します。 これにより、 base が読み取り専用バッファプロトコルをサポートしていないか、バッファセグメントを1つだけ提供していない場合、
TypeError
が発生します。または、 offsetの場合、ValueError
が発生します。 がゼロ未満です。 バッファは base オブジェクトへの参照を保持し、バッファの内容は base オブジェクトのバッファインターフェイスを参照し、位置 offset から始まり、[ X202X] size バイト。 size がPy_END_OF_BUFFER
の場合、新しいバッファーの内容は、 base オブジェクトのエクスポートされたバッファーデータの長さまで拡張されます。バージョン2.5で変更:この関数は、オフセットおよびサイズに
int
タイプを使用していました。 これには、64ビットシステムを適切にサポートするためにコードの変更が必要になる場合があります。
- PyObject *PyBuffer_FromReadWriteObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
新しい書き込み可能なバッファオブジェクトを返します。 パラメータと例外は、 PyBuffer_FromObject()の場合と同様です。 base オブジェクトが書き込み可能なバッファプロトコルをエクスポートしない場合、
TypeError
が発生します。バージョン2.5で変更:この関数は、オフセットおよびサイズに
int
タイプを使用していました。 これには、64ビットシステムを適切にサポートするためにコードの変更が必要になる場合があります。
- PyObject *PyBuffer_FromMemory(void *ptr, Py_ssize_t size)
指定されたサイズで、メモリ内の指定された場所から読み取る新しい読み取り専用バッファオブジェクトを返します。 呼び出し元は、 ptr として渡されたメモリバッファが、返されたバッファオブジェクトが存在する間、割り当てが解除されないようにする責任があります。 size がゼロ未満の場合、
ValueError
を上げます。Py_END_OF_BUFFER
は size パラメーターに渡されない場合があることに注意してください。 その場合、ValueError
が発生します。バージョン2.5で変更:この関数は、サイズに
int
タイプを使用していました。 これには、64ビットシステムを適切にサポートするためにコードの変更が必要になる場合があります。
- PyObject *PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size)
PyBuffer_FromMemory()に似ていますが、返されたバッファーは書き込み可能です。
バージョン2.5で変更:この関数は、サイズに
int
タイプを使用していました。 これには、64ビットシステムを適切にサポートするためにコードの変更が必要になる場合があります。
- PyObject *PyBuffer_New(Py_ssize_t size)
size バイトの独自のメモリバッファを維持する新しい書き込み可能なバッファオブジェクトを返します。
ValueError
は、 size がゼロまたは正でない場合に返されます。 メモリバッファ( PyObject_AsWriteBuffer()によって返される)は特に整列されていないことに注意してください。バージョン2.5で変更:この関数は、サイズに
int
タイプを使用していました。 これには、64ビットシステムを適切にサポートするためにコードの変更が必要になる場合があります。