buffer.md
1> **Источник:** https://python-all.ru/3.16/c-api/buffer.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Протокол буфера89Некоторые объекты, доступные в Python, предоставляют доступ к лежащему в основе массиву памяти или *буферу*. К таким объектам относятся встроенные [`bytes`](https://python-all.ru/3.16/library/stdtypes.html#bytes) и [`bytearray`](https://python-all.ru/3.16/library/stdtypes.html#bytearray), а также некоторые расширяющие типы, например [`array.array`](https://python-all.ru/3.16/library/array.html#array.array). Сторонние библиотеки могут определять собственные типы для специальных целей, таких как обработка изображений или численный анализ.1011Хотя каждый из этих типов имеет свою семантику, их объединяет общая характеристика: все они основаны на возможно большом буфере памяти. В некоторых ситуациях желательно получить прямой доступ к этому буферу без промежуточного копирования.1213Python предоставляет такую возможность на уровне C и Python в виде [протокола буфера](https://python-all.ru/3.16/c-api/buffer.html#bufferobjects). Этот протокол имеет две стороны:1415- На стороне производителя тип может экспортировать «буферный интерфейс», который позволяет объектам этого типа раскрывать информацию о своём базовом буфере. Этот интерфейс описан в разделе [Структуры буферных объектов](https://python-all.ru/3.16/c-api/typeobj.html#buffer-structs); для Python см. [Эмуляция буферных типов](https://python-all.ru/3.16/reference/datamodel.html#python-buffer-protocol).16- На стороне потребителя доступны несколько способов получить указатель на необработанные базовые данные объекта (например, параметр метода). Для Python см. [`memoryview`](https://python-all.ru/3.16/library/stdtypes.html#memoryview).1718Простые объекты, такие как [`bytes`](https://python-all.ru/3.16/library/stdtypes.html#bytes) и [`bytearray`](https://python-all.ru/3.16/library/stdtypes.html#bytearray), предоставляют свой базовый буфер в байт-ориентированной форме. Возможны и другие формы; например, элементы, предоставляемые [`array.array`](https://python-all.ru/3.16/library/array.html#array.array), могут быть многобайтовыми значениями.1920Примером потребителя буферного интерфейса является метод [`write()`](https://python-all.ru/3.16/library/io.html#io.BufferedIOBase.write) файловых объектов: любой объект, который может экспортировать последовательность байтов через буферный интерфейс, может быть записан в файл. В то время как `write()` требуется только доступ на чтение к внутреннему содержимому переданного ему объекта, другие методы, такие как [`readinto()`](https://python-all.ru/3.16/library/io.html#io.BufferedIOBase.readinto), требуют доступа на запись к содержимому своего аргумента. Буферный интерфейс позволяет объектам выборочно разрешать или запрещать экспорт буферов с возможностью чтения-записи и только для чтения.2122Существует два способа для потребителя буферного интерфейса получить буфер над целевым объектом:2324- вызов [`PyObject_GetBuffer()`](https://python-all.ru/3.16/c-api/buffer.html#c.PyObject_GetBuffer) с правильными параметрами;25- вызов [`PyArg_ParseTuple()`](https://python-all.ru/3.16/c-api/arg.html#c.PyArg_ParseTuple) (или одного из его аналогов) с одним из `y*`, `w*` или `s*` [кодов формата](https://python-all.ru/3.16/c-api/arg.html#arg-parsing).2627В обоих случаях [`PyBuffer_Release()`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBuffer_Release) должен быть вызван, когда буфер больше не нужен. Невыполнение этого требования может привести к различным проблемам, таким как утечка ресурсов.2829Добавлено в версии 3.12: Теперь протокол буфера доступен в Python, см. [Эмуляция буферных типов](https://python-all.ru/3.16/reference/datamodel.html#python-buffer-protocol) и [`memoryview`](https://python-all.ru/3.16/library/stdtypes.html#memoryview).3031## Структура буфера3233Структуры буферов (или просто «буферы») полезны как способ предоставления бинарных данных из другого объекта программисту на Python. Их также можно использовать как механизм среза с нулевым копированием. Благодаря возможности ссылаться на блок памяти, можно довольно легко предоставить любые данные программисту на Python. Память может быть большим константным массивом в C-расширении, необработанным блоком памяти для манипуляций перед передачей в библиотеку операционной системы или использоваться для передачи структурированных данных в их родном формате в памяти.3435В отличие от большинства типов данных, предоставляемых интерпретатором Python, буферы не являются указателями [`PyObject`](https://python-all.ru/3.16/c-api/structures.html#c.PyObject), а представляют собой простые структуры C. Это позволяет очень просто создавать и копировать их. Когда нужна универсальная обёртка вокруг буфера, можно создать объект [memoryview](https://python-all.ru/3.16/c-api/memoryview.html#memoryview-objects).3637Краткие инструкции по написанию экспортирующего объекта см. в разделе [Структуры буферных объектов](https://python-all.ru/3.16/c-api/typeobj.html#buffer-structs). Для получения буфера см. [`PyObject_GetBuffer()`](https://python-all.ru/3.16/c-api/buffer.html#c.PyObject_GetBuffer).3839#### `type Py_buffer`4041*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) (включая все члены) с версии 3.11.*4243#### `void *buf`4445Указатель на начало логической структуры, описываемой полями буфера. Это может быть любое место в базовом физическом блоке памяти экспортёра. Например, при отрицательном [`strides`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.strides) значение может указывать на конец блока памяти.4647Для [непрерывных](https://python-all.ru/3.16/glossary.html#term-contiguous) массивов значение указывает на начало блока памяти.4849#### `PyObject *obj`5051Новая ссылка на экспортирующий объект. Ссылка принадлежит потребителю и автоматически освобождается (т.е. счётчик ссылок уменьшается) и устанавливается в `NULL` вызовом [`PyBuffer_Release()`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBuffer_Release). Это поле эквивалентно возвращаемому значению любой стандартной функции C-API.5253В особом случае для *временных* буферов, обёрнутых в [`PyMemoryView_FromBuffer()`](https://python-all.ru/3.16/c-api/memoryview.html#c.PyMemoryView_FromBuffer) или [`PyBuffer_FillInfo()`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBuffer_FillInfo), это поле равно `NULL`. В целом экспортирующие объекты НЕ ДОЛЖНЫ использовать эту схему.5455#### `Py_ssize_t len`5657`product(shape) * itemsize`. Для непрерывных массивов это длина базового блока памяти. Для разрывных массивов это длина, которую имела бы логическая структура при копировании в непрерывное представление.5859Обращение к `((char *)buf)[0] up to ((char *)buf)[len-1]` допустимо только в том случае, если буфер получен через запрос, гарантирующий непрерывность. В большинстве случаев такой запрос будет [`PyBUF_SIMPLE`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_SIMPLE) или [`PyBUF_WRITABLE`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_WRITABLE).6061#### `int readonly`6263Индикатор, доступен ли буфер только для чтения. Это поле управляется флагом [`PyBUF_WRITABLE`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_WRITABLE).6465#### `Py_ssize_t itemsize`6667Размер одного элемента в байтах. То же, что и значение [`struct.calcsize()`](https://python-all.ru/3.16/library/struct.html#struct.calcsize), вызванное для значений, не являющихся `NULL` [`format`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.format).6869Важное исключение: если потребитель запрашивает буфер без флага [`PyBUF_FORMAT`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_FORMAT), [`format`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.format) будет установлен в `NULL`, но [`itemsize`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.itemsize) всё ещё содержит значение для исходного формата.7071Если [`shape`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.shape) присутствует, равенство `product(shape) * itemsize == len` по-прежнему выполняется, и потребитель может использовать [`itemsize`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.itemsize) для навигации по буферу.7273Если [`shape`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.shape) равен `NULL` в результате запроса [`PyBUF_SIMPLE`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_SIMPLE) или [`PyBUF_WRITABLE`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_WRITABLE), потребитель должен игнорировать [`itemsize`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.itemsize) и считать `itemsize == 1`.7475#### `char *format`7677Строка с завершающим *NULL* в синтаксисе модуля [`struct`](https://python-all.ru/3.16/library/struct.html#module-struct), описывающая содержимое одного элемента. Если это `NULL`, предполагается `"B"` (беззнаковые байты).7879Это поле управляется флагом [`PyBUF_FORMAT`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_FORMAT).8081#### `int ndim`8283Количество измерений, которые память представляет в виде n-мерного массива. Если равно `0`, [`buf`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.buf) указывает на единственный элемент, представляющий скаляр. В этом случае [`shape`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.shape), [`strides`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.strides) и [`suboffsets`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.suboffsets) ДОЛЖНЫ быть равны `NULL`. Максимальное количество измерений задаётся [`PyBUF_MAX_NDIM`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_MAX_NDIM).8485#### `Py_ssize_t *shape`8687Массив из [`Py_ssize_t`](https://python-all.ru/3.16/c-api/intro.html#c.Py_ssize_t) длиной [`ndim`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.ndim), указывающий форму памяти в виде n-мерного массива. Обратите внимание, что `shape[0] * ... * shape[ndim-1] * itemsize` ДОЛЖНО быть равно [`len`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.len).8889Значения формы ограничены `shape[n] >= 0`. Случай `shape[n] == 0` требует особого внимания. Дополнительную информацию см. в разделе [сложные массивы](https://python-all.ru/3.16/c-api/buffer.html#complex-arrays).9091Массив формы доступен потребителю только для чтения.9293#### `Py_ssize_t *strides`9495Массив из [`Py_ssize_t`](https://python-all.ru/3.16/c-api/intro.html#c.Py_ssize_t) длиной [`ndim`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.ndim), задающий количество байтов, которое нужно пропустить, чтобы перейти к новому элементу в каждом измерении.9697Значения шага могут быть любыми целыми числами. Для обычных массивов шаги обычно положительны, но потребитель ДОЛЖЕН уметь обрабатывать случай `strides[n] <= 0`. Дополнительную информацию см. в разделе [сложные массивы](https://python-all.ru/3.16/c-api/buffer.html#complex-arrays).9899Массив шагов доступен потребителю только для чтения.100101#### `Py_ssize_t *suboffsets`102103Массив из [`Py_ssize_t`](https://python-all.ru/3.16/c-api/intro.html#c.Py_ssize_t) длиной [`ndim`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.ndim). Если `suboffsets[n] >= 0`, значения, хранящиеся по n-му измерению, являются указателями, и значение смещения подмассива указывает, сколько байтов добавить к каждому указателю после разыменования. Отрицательное значение смещения подмассива означает, что разыменование производиться не должно (шаг по непрерывному блоку памяти).104105Если все смещения подмассивов отрицательны (т.е. разыменование не требуется), то это поле должно быть `NULL` (значение по умолчанию).106107Такой тип представления массива используется библиотекой Python Imaging Library (PIL). Дополнительную информацию о доступе к элементам такого массива см. в разделе [сложные массивы](https://python-all.ru/3.16/c-api/buffer.html#complex-arrays).108109Массив смещений подмассивов доступен потребителю только для чтения.110111#### `void *internal`112113Предназначено для внутреннего использования экспортирующим объектом. Например, экспортёр может переинтерпретировать это значение как целое число и использовать для хранения флагов о том, нужно ли освобождать массивы shape, strides и suboffsets при освобождении буфера. Потребитель НЕ ДОЛЖЕН изменять это значение.114115Константы:116117#### `PyBUF_MAX_NDIM`118119*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.*120121Максимальное количество измерений, представляемых памятью. Экспортёры ОБЯЗАНЫ соблюдать это ограничение, потребители многомерных буферов ДОЛЖНЫ уметь работать с количеством измерений до `PyBUF_MAX_NDIM`. В настоящее время установлено 64.122123## Типы запросов буфера124125Обычно буферы получают, отправляя запрос буфера экспортирующему объекту через [`PyObject_GetBuffer()`](https://python-all.ru/3.16/c-api/buffer.html#c.PyObject_GetBuffer). Поскольку сложность логической структуры памяти может сильно различаться, потребитель использует аргумент *flags* для указания точного типа буфера, с которым он может работать.126127Все поля [`Py_buffer`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer) однозначно определяются типом запроса.128129### поля, не зависящие от запроса130131Следующие поля не зависят от *flags* и всегда должны заполняться корректными значениями: [`obj`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.obj), [`buf`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.buf), [`len`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.len), [`itemsize`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.itemsize), [`ndim`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.ndim).132133### readonly, format134135> #### `PyBUF_WRITABLE`136>137> *Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.*138>139> Управляет полем [`readonly`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.readonly). Если установлен, экспортёр ОБЯЗАН предоставить буфер для записи, иначе сообщить об ошибке. В противном случае экспортёр МОЖЕТ предоставить буфер только для чтения или для записи, но выбор ДОЛЖЕН быть согласован для всех потребителей. Например, [PyBUF\_SIMPLE](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_SIMPLE) | [PyBUF\_WRITABLE](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_WRITABLE) может использоваться для запроса простого буфера для записи.140>141> #### `PyBUF_WRITEABLE`142>143> Это псевдоним [`PyBUF_WRITABLE`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_WRITABLE).144>145> [Мягкое устаревание](https://python-all.ru/3.16/glossary.html#term-soft-deprecated) начиная с версии 3.13.146>147> #### `PyBUF_FORMAT`148>149> *Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.*150>151> Управляет полем [`format`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.format). Если установлен, это поле ДОЛЖНО быть заполнено корректно. В противном случае это поле ДОЛЖНО быть `NULL`.152153[`PyBUF_WRITABLE`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_WRITABLE) можно комбинировать (|) с любыми флагами из следующего раздела. Поскольку [`PyBUF_SIMPLE`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_SIMPLE) определён как 0, `PyBUF_WRITABLE` может использоваться как самостоятельный флаг для запроса простого буфера для записи.154155[`PyBUF_FORMAT`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_FORMAT) ДОЛЖЕН комбинироваться (|) с любыми флагами, кроме [`PyBUF_SIMPLE`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_SIMPLE), поскольку последний уже подразумевает формат `B` (unsigned bytes). `PyBUF_FORMAT` нельзя использовать самостоятельно.156157### shape, strides, suboffsets158159Флаги, управляющие логической структурой памяти, перечислены в порядке убывания сложности. Обратите внимание, что каждый флаг содержит все биты флагов, расположенных ниже него.160161| Запрос | shape | strides | suboffsets |162| --- | --- | --- | --- |163| PyBUF\_INDIRECT *Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | да | да | при необходимости |164| PyBUF\_STRIDES *Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | да | да | NULL |165| PyBUF\_ND *Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | да | NULL | NULL |166| PyBUF\_SIMPLE *Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | NULL | NULL | NULL |167168### запросы непрерывности169170[Непрерывность](https://python-all.ru/3.16/glossary.html#term-contiguous) по C или Fortran может быть явно запрошена, с информацией о шагах и без неё. Без информации о шагах буфер должен быть непрерывным по C.171172| Запрос | форма | шаги | подсмещения | contig |173| --- | --- | --- | --- | --- |174| PyBUF\_C\_CONTIGUOUS *Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | да | да | NULL | C |175| PyBUF\_F\_CONTIGUOUS *Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | да | да | NULL | F |176| PyBUF\_ANY\_CONTIGUOUS *Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | yes | yes | NULL | C or F |177| [`PyBUF_ND`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_ND) | yes | NULL | NULL | C |178179### составные запросы180181Все возможные запросы полностью определяются некоторой комбинацией флагов из предыдущего раздела. Для удобства протокол буфера предоставляет часто используемые комбинации в виде отдельных флагов.182183В следующей таблице *U* обозначает неопределённую непрерывность. Потребителю придётся вызвать [`PyBuffer_IsContiguous()`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBuffer_IsContiguous), чтобы определить непрерывность.184185| Запрос | форма | шаги | подсмещения | непрерывность | только для чтения | формат |186| --- | --- | --- | --- | --- | --- | --- |187| PyBUF\_FULL *Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | yes | yes | если необходимо | U | 0 | yes |188| PyBUF\_FULL\_RO *Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | yes | yes | если необходимо | U | 1 or 0 | yes |189| PyBUF\_RECORDS *Входит в состав [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | да | да | NULL | U | 0 | да |190| PyBUF\_RECORDS\_RO *Входит в состав [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | да | да | NULL | U | 1 или 0 | да |191| PyBUF\_STRIDED *Входит в состав [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | да | да | NULL | U | 0 | NULL |192| PyBUF\_STRIDED\_RO *Входит в состав [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | да | да | NULL | U | 1 или 0 | NULL |193| PyBUF\_CONTIG *Входит в состав [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.* | да | NULL | NULL | C | 0 | NULL |194| PyBUF\_CONTIG\_RO *Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) с версии 3.11.* | да | NULL | NULL | C | 1 или 0 | NULL |195196## Комплексные массивы197198### В стиле NumPy: форма и шаги199200Логическая структура массивов в стиле NumPy определяется [`itemsize`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.itemsize), [`ndim`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.ndim), [`shape`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.shape) и [`strides`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.strides).201202Если `ndim == 0`, то область памяти, на которую указывает [`buf`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.buf), интерпретируется как скаляр размера [`itemsize`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.itemsize). В этом случае и [`shape`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.shape), и [`strides`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.strides) равны `NULL`.203204Если [`strides`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.strides) равно `NULL`, массив интерпретируется как стандартный n-мерный C-массив. В противном случае потребитель должен обращаться к n-мерному массиву следующим образом:205206```c207ptr = (char *)buf + indices[0] * strides[0] + ... + indices[n-1] * strides[n-1];208item = *((typeof(item) *)ptr);209```210211Как отмечалось выше, [`buf`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.buf) может указывать на любую позицию в реальном блоке памяти. Экспортер может проверить корректность буфера с помощью этой функции:212213```python214def verify_structure(memlen, itemsize, ndim, shape, strides, offset):215 """Проверить, что параметры представляют допустимый массив в пределах216 границ выделенной памяти:217 char *mem: начало физического блока памяти218 memlen: длина физического блока памяти219 offset: (char *)buf - mem220 """221 if offset % itemsize:222 return False223 if offset < 0 or offset+itemsize > memlen:224 return False225 if any(v % itemsize for v in strides):226 return False227228 if ndim <= 0:229 return ndim == 0 and not shape and not strides230 if 0 in shape:231 return True232233 imin = sum(strides[j]*(shape[j]-1) for j in range(ndim)234 if strides[j] <= 0)235 imax = sum(strides[j]*(shape[j]-1) for j in range(ndim)236 if strides[j] > 0)237238 return 0 <= offset+imin and offset+imax+itemsize <= memlen239```240241### В стиле PIL: форма, шаги и suboffsets242243В дополнение к обычным элементам массивы в стиле PIL могут содержать указатели, по которым нужно перейти, чтобы получить следующий элемент в измерении. Например, обычный трехмерный C-массив `char v[2][2][3]` можно также рассматривать как массив из 2 указателей на 2 двумерных массива: `char (*v[2])[2][3]`. В представлении suboffsets эти два указателя могут быть встроены в начало [`buf`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.buf), указывая на два `char x[2][3]` массива, которые могут находиться в любом месте памяти.244245Вот функция, которая возвращает указатель на элемент в N-мерном массиве, на который указывает N-мерный индекс, при наличии как ненулевых `NULL` шагов, так и suboffsets:246247```c248void *get_item_pointer(int ndim, void *buf, Py_ssize_t *strides,249 Py_ssize_t *suboffsets, Py_ssize_t *indices) {250 char *pointer = (char*)buf;251 int i;252 for (i = 0; i < ndim; i++) {253 pointer += strides[i] * indices[i];254 if (suboffsets[i] >=0 ) {255 pointer = *((char**)pointer) + suboffsets[i];256 }257 }258 return (void*)pointer;259}260```261262## Функции, связанные с буфером263264#### `int PyObject_CheckBuffer(PyObject *obj)`265266*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) с версии 3.11.*267268Возвращает `1`, если *obj* поддерживает интерфейс буфера, иначе `0`. Когда возвращается `1`, это не гарантирует, что [`PyObject_GetBuffer()`](https://python-all.ru/3.16/c-api/buffer.html#c.PyObject_GetBuffer) выполнится успешно. Эта функция всегда завершается успешно.269270#### `int PyObject_GetBuffer(PyObject *exporter, Py_buffer *view, int flags)`271272*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) с версии 3.11.*273274Отправляет запрос *exporter* для заполнения *view* в соответствии с *flags*. Если экспортер не может предоставить буфер точного типа, он ДОЛЖЕН вызвать [`BufferError`](https://python-all.ru/3.16/library/exceptions.html#BufferError), установить `view->obj` в `NULL` и вернуть `-1`.275276В случае успеха заполняет *view*, устанавливает `view->obj` в новую ссылку на *exporter* и возвращает 0. В случае цепочечных поставщиков буфера, которые перенаправляют запросы одному объекту, `view->obj` МОЖЕТ ссылаться на этот объект вместо *exporter* (см. [Структуры буферных объектов](https://python-all.ru/3.16/c-api/typeobj.html#buffer-structs)).277278Успешные вызовы [`PyObject_GetBuffer()`](https://python-all.ru/3.16/c-api/buffer.html#c.PyObject_GetBuffer) должны быть парными с вызовами [`PyBuffer_Release()`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBuffer_Release), как и в случае с `malloc()` и `free()`. Таким образом, после того как потребитель закончил работу с буфером, `PyBuffer_Release()` должен быть вызван ровно один раз.279280#### `void PyBuffer_Release(Py_buffer *view)`281282*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) с версии 3.11.*283284Освобождает буфер *view* и освобождает [сильную ссылку](https://python-all.ru/3.16/glossary.html#term-strong-reference) (т.е. уменьшает счетчик ссылок) на поддерживающий объект представления, `view->obj`. Эта функция ДОЛЖНА вызываться, когда буфер больше не используется, иначе могут возникнуть утечки ссылок.285286Вызов этой функции для буфера, который не был получен через [`PyObject_GetBuffer()`](https://python-all.ru/3.16/c-api/buffer.html#c.PyObject_GetBuffer), является ошибкой.287288#### `Py_ssize_t PyBuffer_SizeFromFormat(const char *format)`289290*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) с версии 3.11.*291292Возвращает подразумеваемый [`itemsize`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.itemsize) из [`format`](https://python-all.ru/3.16/c-api/buffer.html#c.Py_buffer.format). При ошибке вызывает исключение и возвращает -1.293294Добавлено в версии 3.9.295296#### `int PyBuffer_IsContiguous(const Py_buffer *view, char order)`297298*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.*299300Возвращает `1`, если память, определяемая *view*, является C-style (*order* равен `'C'`) или Fortran-style (*order* равен `'F'`) [непрерывной (contiguous)](https://python-all.ru/3.16/glossary.html#term-contiguous), или любой из них (*order* равен `'A'`). Иначе возвращает `0`. Эта функция всегда завершается успешно.301302#### `void *PyBuffer_GetPointer(const Py_buffer *view, const Py_ssize_t *indices)`303304*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.*305306Получает область памяти, на которую указывают *indices* внутри заданного *view*. *indices* должен указывать на массив из `view->ndim` индексов.307308#### `int PyBuffer_FromContiguous(const Py_buffer *view, const void *buf, Py_ssize_t len, char order)`309310*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.*311312Копирует *len* непрерывных байтов из *buf* в *view*. *order* может быть `'C'`, `'F'` или `'A'` (для упорядочения в стиле C или Fortran, либо любого из них). При успехе возвращается `0`, при ошибке – `-1`.313314#### `int PyBuffer_ToContiguous(void *buf, const Py_buffer *src, Py_ssize_t len, char order)`315316*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.*317318Копирует *len* байтов из *src* в его непрерывное представление в *buf*. *order* может быть `'C'`, `'F'` или `'A'` (для упорядочения в стиле C или Fortran, либо любого из них). `0` возвращается при успехе, `-1` при ошибке.319320Эта функция завершается ошибкой, если *len* != *src-\>len*.321322#### `int PyObject_CopyData(PyObject *dest, PyObject *src)`323324*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.*325326Копирует данные из буфера *src* в буфер *dest*. Может выполнять преобразование между буферами в стиле C и Fortran.327328`0` возвращается при успехе, `-1` при ошибке.329330#### `void PyBuffer_FillContiguousStrides(int ndims, Py_ssize_t *shape, Py_ssize_t *strides, int itemsize, char order)`331332*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.*333334Заполняет массив *strides* шагами в байтах (byte-strides) для [непрерывного](https://python-all.ru/3.16/glossary.html#term-contiguous) массива заданной формы с заданным количеством байтов на элемент (в стиле C, если *order* равен `'C'`, или в стиле Fortran, если *order* равен `'F'`).335336#### `int PyBuffer_FillInfo(Py_buffer *view, PyObject *exporter, void *buf, Py_ssize_t len, int readonly, int flags)`337338*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.11.*339340Обрабатывает запросы буфера для экспортёра, который хочет предоставить *buf* размером *len* с настройкой возможности записи в соответствии с *readonly*. *buf* интерпретируется как последовательность байтов без знака.341342Аргумент *flags* указывает тип запроса. Эта функция всегда заполняет *view* в соответствии с флагами, за исключением случаев, когда *buf* помечен как доступный только для чтения и в *flags* установлен [`PyBUF_WRITABLE`](https://python-all.ru/3.16/c-api/buffer.html#c.PyBUF_WRITABLE).343344При успехе устанавливает `view->obj` в новую ссылку на *exporter* и возвращает 0. В противном случае возбуждает [`BufferError`](https://python-all.ru/3.16/library/exceptions.html#BufferError), устанавливает `view->obj` в `NULL` и возвращает `-1`.345346Если эта функция используется как часть [getbufferproc](https://python-all.ru/3.16/c-api/typeobj.html#buffer-structs), *exporter* ДОЛЖЕН быть установлен на экспортирующий объект, а *flags* должны передаваться без изменений. В противном случае *exporter* ДОЛЖЕН быть `NULL`.347