Содержание страницы
Буферы и объекты memoryview¶Buffers 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 при освобождении буфера. Потребитель никогда не должен изменять это значение.
-
void *
Объекты MemoryView¶MemoryView 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не разрешено.
Объекты буфера старого стиля¶Old-style buffer objects
Дополнительная информация о старом интерфейсе буфера приведена в разделе Структуры объектов буфера, в описании PyBufferProcs.
«Объект буфера» определяется в заголовочном файле bufferobject.h (включаемом через Python.h). Эти объекты очень похожи на строковые объекты на уровне программирования на Python: они поддерживают срезы, индексацию, конкатенацию и некоторые другие стандартные строковые операции. Однако их данные могут поступать из одного из двух источников: из блока памяти или из другого объекта, который экспортирует интерфейс буфера.
Объекты буфера полезны как способ предоставления данных из интерфейса буфера другого объекта программисту на Python. Они также могут использоваться как механизм срезов с нулевым копированием. Благодаря возможности ссылаться на блок памяти, можно довольно легко предоставить любые данные программисту на Python. Память может быть большим постоянным массивом в расширении на C, сырым блоком памяти для манипуляций перед передачей в библиотеку операционной системы или использоваться для передачи структурированных данных в их родном формате в памяти.
-
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-битных систем.