Документация Python неофициальный перевод
Содержание страницы

Буферные объектыBuffer Objects

Объекты Python, реализованные на C, могут экспортировать группу функций, называемую «буферным интерфейсом». Эти функции могут использоваться объектом для предоставления своих данных в сыром, байт-ориентированном формате. Клиенты объекта могут использовать буферный интерфейс для прямого доступа к данным объекта без необходимости их предварительного копирования.

Два примера объектов, поддерживающих буферный интерфейс: строки и массивы. Строка предоставляет содержимое символов в байт-ориентированной форме буферного интерфейса. Массив также может предоставлять свое содержимое, но следует помнить, что элементы массива могут быть многобайтовыми.

Примером потребителя буферного интерфейса является метод write() файлового объекта. Любой объект, способный экспортировать последовательность байтов через буферный интерфейс, может быть записан в файл. Существует ряд кодов формата для PyArg_ParseTuple(), которые работают с буферным интерфейсом объекта, возвращая данные из целевого объекта.

Начиная с версии 1.6, Python предоставлял буферные объекты на уровне Python и C-API буфера, чтобы любой встроенный или пользовательский тип мог предоставлять свои характеристики. Однако оба они были объявлены устаревшими из-за различных недостатков и официально удалены в Python 3.0 в пользу нового C-API буфера и нового объекта на уровне Python с именем memoryview.

Новый буферный API был перенесен в Python 2.6, а объект memoryview – в Python 2.7. Настоятельно рекомендуется использовать их вместо старых API, если только совместимость не вынуждает использовать старые.

Структура Py_buffer нового стиляThe new-style Py_buffer struct

Py_buffer
void *buf
Указатель на начало памяти объекта.
Py_ssize_t len
Общая длина памяти в байтах.
int readonly
Индикатор того, является ли буфер доступным только для чтения.
const char *format
Строка, завершающаяся NULL, в синтаксисе модуля struct, описывающая содержимое элементов, доступных через буфер. Если это NULL, то подразумевается "B" (беззнаковые байты).
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. Если эти числа suboffset больше или равны 0, то значение, хранящееся по указанному измерению, является указателем, а значение suboffset определяет, сколько байтов добавить к указателю после разыменования. Отрицательное значение suboffset означает, что разыменование не должно выполняться (шаг в непрерывном блоке памяти).

Вот функция, которая возвращает указатель на элемент в N-мерном массиве, на который указывает N-мерный индекс, при наличии как ненулевых strides, так и suboffsets:

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
Это поле предназначено для внутреннего использования экспортирующим объектом. Например, оно может быть переинтерпретировано как целое число экспортером и использоваться для хранения флагов о том, нужно ли освобождать массивы shape, strides и suboffsets при освобождении буфера. Потребитель никогда не должен изменять это значение.

Объекты буфера старого стиляOld-style buffer objects

Дополнительная информация о буферном интерфейсе приведена в разделе Структуры буферных объектов, в описании PyBufferProcs.

«Буферный объект» определяется в заголовочном файле bufferobject.h (включаемом через Python.h). На уровне программирования на Python эти объекты очень похожи на строковые: они поддерживают срезы, индексацию, конкатенацию и некоторые другие стандартные операции со строками. Однако их данные могут поступать из одного из двух источников: из блока памяти или из другого объекта, который экспортирует буферный интерфейс.

Объекты буфера полезны как способ предоставления данных из интерфейса буфера другого объекта программисту на Python. Они также могут использоваться как механизм срезов с нулевым копированием. Благодаря возможности ссылаться на блок памяти, можно довольно легко предоставить любые данные программисту на Python. Память может быть большим постоянным массивом в расширении на C, сырым блоком памяти для манипуляций перед передачей в библиотеку операционной системы или использоваться для передачи структурированных данных в их родном формате в памяти.

PyBufferObject
Этот подтип PyObject представляет буферный объект.
PyTypeObject PyBuffer_Type

Экземпляр PyTypeObject, представляющий тип буфера Python; это тот же объект, что и buffer и types.BufferType на уровне Python.

int Py_END_OF_BUFFER
Эту константу можно передавать в качестве параметра size функциям PyBuffer_FromObject() или PyBuffer_FromReadWriteObject(). Она указывает, что новый PyBufferObject должен ссылаться на объект base от указанного offset до конца его экспортируемого буфера. Использование этой константы позволяет вызывающему коду не запрашивать длину у объекта base.
int PyBuffer_Check(PyObject *p)
Возвращает true, если аргумент имеет тип PyBuffer_Type.
PyObject* PyBuffer_FromObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
Возвращаемое значение: новая ссылка.

Возвращает новый буферный объект только для чтения. Возбуждается TypeError, если base не поддерживает протокол буфера только для чтения или не предоставляет ровно один сегмент буфера, и возбуждается ValueError, если offset меньше нуля. Буфер будет содержать ссылку на объект base, а содержимое буфера будет ссылаться на буферный интерфейс объекта base, начиная с позиции offset и занимая size байт. Если size равно Py_END_OF_BUFFER, то содержимое нового буфера распространяется на всю длину экспортированных буферных данных объекта base.

Изменено в версии 2.5: Для параметров offset и size в этой функции использовался тип int. Это может потребовать изменений в вашем коде для корректной поддержки 64-разрядных систем.

PyObject* PyBuffer_FromReadWriteObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
Возвращаемое значение: новая ссылка.

Возвращает новый буферный объект, доступный для записи. Параметры и исключения аналогичны PyBuffer_FromObject(). Если объект base не экспортирует протокол буфера, доступного для записи, то возбуждается TypeError.

Изменено в версии 2.5: Для параметров offset и size в этой функции использовался тип int. Это может потребовать изменений в вашем коде для корректной поддержки 64-разрядных систем.

PyObject* PyBuffer_FromMemory(void *ptr, Py_ssize_t size)
Возвращаемое значение: новая ссылка.

Возвращает новый буферный объект только для чтения, который читает данные из указанного расположения в памяти с заданным размером. Вызывающий обязан гарантировать, что буфер памяти, переданный как ptr, не будет освобождён, пока существует возвращаемый буферный объект. Возбуждается ValueError, если size меньше нуля. Обратите внимание, что Py_END_OF_BUFFER нельзя передавать в качестве параметра size; в этом случае будет возбуждено ValueError.

Изменено в версии 2.5: Для параметра size в этой функции использовался тип int. Это может потребовать изменений в вашем коде для корректной поддержки 64-разрядных систем.

PyObject* PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size)
Возвращаемое значение: новая ссылка.

Аналогична PyBuffer_FromMemory(), но возвращаемый буфер доступен для записи.

Изменено в версии 2.5: Для параметра size в этой функции использовался тип int. Это может потребовать изменений в вашем коде для корректной поддержки 64-разрядных систем.

PyObject* PyBuffer_New(Py_ssize_t size)
Возвращаемое значение: новая ссылка.

Return a new writable buffer object that maintains its own memory buffer of size bytes. ValueError is returned if size is not zero or positive. Note that the memory buffer (as returned by PyObject_AsWriteBuffer()) is not specifically aligned.

Изменено в версии 2.5: Раньше эта функция использовала тип int для size. Это может потребовать изменений в вашем коде для корректной поддержки 64-битных систем.