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

Буферы и объекты memoryviewBuffers and Memoryview Objects

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

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

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

Начиная с версии 1.6, Python предоставляет буферные объекты на уровне Python и буферный API на уровне C, чтобы любой встроенный или определённый пользователем тип мог предоставлять свои характеристики. Однако оба были объявлены устаревшими из-за различных недостатков и официально удалены в Python 3 в пользу нового буферного API на уровне C и нового объекта на уровне 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 указывает, что разыменования не должно происходить (шаговый доступ в непрерывном блоке памяти).

Если все под-смещения отрицательны (т.е. разыменование не требуется), то это поле должно быть NULL (значение по умолчанию).

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

Объекты MemoryViewMemoryView objects

Новое в версии 2.7.

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

PyObject *PyMemoryView_FromObject(PyObject *obj)

Создаёт объект memoryview из объекта, определяющего новый интерфейс буфера.

PyObject *PyMemoryView_FromBuffer(Py_buffer *view)

Создаёт объект memoryview, оборачивающий заданную структуру информации о буфере view. Объект memoryview затем становится владельцем буфера, то есть не следует пытаться освобождать его самостоятельно: он будет освобождён при удалении объекта memoryview.

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

Создаёт объект memoryview для непрерывного блока памяти (в порядке «C» или «Фортран» order) на основе объекта, определяющего буферный интерфейс. Если память непрерывна, объект memoryview указывает на исходную память. В противном случае создаётся копия, и memoryview указывает на новый объект bytes.

int PyMemoryView_Check(PyObject *obj)

Возвращает true, если объект obj является объектом memoryview. В настоящее время создание подклассов memoryview не разрешено.

Py_buffer *PyMemoryView_GET_BUFFER(PyObject *obj)

Возвращает указатель на структуру информации о буфере, обёрнутую заданным объектом. Объект должен быть экземпляром memoryview; этот макрос не проверяет его тип, это необходимо делать самостоятельно, иначе возможны сбои.

Объекты буфера старого стиля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: Эта функция использовала тип int для offset и size. Это может потребовать изменений в вашем коде для корректной поддержки 64-битных систем.

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

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

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

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

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

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

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

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

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

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

Возвращает новый буферный объект для записи, который управляет собственным буфером памяти размером size байт. ValueError возвращается, если size не является нулём или положительным числом. Обратите внимание, что буфер памяти (возвращаемый PyObject_AsWriteBuffer()) не имеет специального выравнивания.

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