> **Источник:** https://python-all.ru/3.0/c-api/buffer.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

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

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

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

Примером использования буферного интерфейса является метод `write()` файлового объекта. Любой объект, который может экспортировать последовательность байтов через буферный интерфейс, может быть записан в файл. Существует ряд кодов формата для [`PyArg_ParseTuple`](https://python-all.ru/3.0/c-api/arg.html#PyArg_ParseTuple), которые работают с буферным интерфейсом объекта, возвращая данные из целевого объекта.

Дополнительная информация о буферном интерфейсе приведена в разделе [*Структуры буферных объектов*](https://python-all.ru/3.0/c-api/typeobj.html#buffer-structs), в описании [`PyBufferProcs`](https://python-all.ru/3.0/c-api/typeobj.html#PyBufferProcs).

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

**\[Py\_buffer\]`Py_buffer`**

**\[buf\]void \*`buf`**

Указатель на начало памяти объекта.

**Py\_ssize\_t `len`**

Общая длина памяти в байтах.

**\[readonly\]int `readonly`**

Индикатор того, является ли буфер доступным только для чтения.

**const char \*`format`**

Строка, завершающаяся нулём

*NULL*

, в синтаксисе стиля модуля

[`struct`](https://python-all.ru/3.0/library/struct.html#module-struct)

, задающая содержимое элементов, доступных через буфер. Если это

*NULL*

, то предполагается

`"B"`

(беззнаковые байты).

**\[ndim\]int `ndim`**

Количество измерений, которые память представляет как многомерный массив. Если оно равно 0,

[`strides`](https://python-all.ru/3.0/c-api/buffer.html#strides)

и

[`suboffsets`](https://python-all.ru/3.0/c-api/buffer.html#suboffsets)

должны быть

*NULL*

.

**\[shape\]Py\_ssize\_t \*`shape`**

Массив

`Py_ssize_t`

длиной

[`ndim`](https://python-all.ru/3.0/c-api/buffer.html#ndim)

, задающий форму памяти как многомерного массива. Обратите внимание, что

`((*shape)[0] * ... * (*shape)[ndims-1])*itemsize`

должно быть равно

`len`

.

**\[strides\]Py\_ssize\_t \*`strides`**

Массив

`Py_ssize_t`

длиной

[`ndim`](https://python-all.ru/3.0/c-api/buffer.html#ndim)

, задающий количество байтов, которое нужно пропустить, чтобы перейти к новому элементу в каждом измерении.

**\[suboffsets\]Py\_ssize\_t \*`suboffsets`**

Массив `Py_ssize_t` длиной [`ndim`](https://python-all.ru/3.0/c-api/buffer.html#ndim). Если эти числа suboffset больше или равны 0, то значение, хранящееся по указанному измерению, является указателем, а значение suboffset определяет, сколько байтов добавить к указателю после разыменования. Отрицательное значение suboffset означает, что разыменование не должно выполняться (шаг в непрерывном блоке памяти).

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

```c
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;
 }
```

**\[itemsize\]Py\_ssize\_t `itemsize`**

Это хранилище для размера элемента (в байтах) каждого элемента разделяемой памяти. Технически оно необязательно, так как его можно получить с помощью

[`PyBuffer_SizeFromFormat`](https://python-all.ru/3.0/c-api/buffer.html#PyBuffer_SizeFromFormat)

, однако экспортёр может знать эту информацию без разбора строки формата, и необходимо знать размер элемента для правильной интерпретации шагов (striding). Поэтому сохранение его более удобно и быстрее.

**\[internal\]void \*`internal`**

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

## Функции, связанные с буферами

**\[PyObject\_CheckBuffer\]int `PyObject_CheckBuffer`([PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*obj*)**

Возвращает 1, если

*obj*

поддерживает буферный интерфейс, иначе 0.

**\[PyObject\_GetBuffer\]int `PyObject_GetBuffer`([PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*obj*, [PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*view*, int *flags*)**

Экспортирует *obj* в [`Py_buffer`](https://python-all.ru/3.0/c-api/buffer.html#Py_buffer), *view*. Эти аргументы никогда не должны быть *NULL*. Аргумент *flags* представляет собой битовое поле, указывающее, с каким типом буфера готов работать вызывающий код, и, следовательно, какой тип буфера разрешено возвращать экспортёру. Буферный интерфейс допускает сложные возможности совместного использования памяти, но некоторые вызывающие стороны могут не справиться со всей сложностью и могут захотеть проверить, позволит ли экспортёр им использовать более простое представление своей памяти.

Некоторые экспортёры могут не иметь возможности разделять память любым возможным способом и могут вызывать ошибки, чтобы сообщить некоторым потребителям, что что-то просто невозможно. Эти ошибки должны быть `BufferError`, если только нет другой ошибки, которая на самом деле вызывает проблему. Экспортёр может использовать информацию из flags, чтобы упростить заполнение структуры [`Py_buffer`](https://python-all.ru/3.0/c-api/buffer.html#Py_buffer) значениями, отличными от стандартных, и/или вызвать ошибку, если объект не может поддерживать более простое представление своей памяти.

0 возвращается в случае успеха, -1 – при ошибке.

В следующей таблице приведены возможные значения аргумента *flags*.

| Флаг | Описание |
| --- | --- |
| `PyBUF_SIMPLE` | Это состояние флага по умолчанию. Возвращаемый буфер может иметь или не иметь память для записи. Формат данных будет считаться беззнаковыми байтами. Это «автономная» константа флага. Её никогда не нужно комбинировать с другими с помощью оператора '\|'. Экспортёр вызовет ошибку, если не сможет предоставить такой непрерывный буфер байтов. |
| `PyBUF_WRITABLE` | Возвращаемый буфер должен быть доступен для записи. Если это не так, вызывается ошибка. |
| `PyBUF_STRIDES` | Это подразумевает `PyBUF_ND`. Возвращаемый буфер должен предоставлять информацию о шагах (т.е. шаги не могут быть NULL). Используется, когда потребитель может работать со страйдед-массивами (с разрывами). Работа с шагами автоматически подразумевает, что доступна информация о форме. Экспортёр может вызвать ошибку, если страйдед-представление данных невозможно (например, без suboffsets). |
| `PyBUF_ND` | Возвращаемый буфер должен предоставлять информацию о форме. Память считается C-стиль непрерывной (последнее измерение меняется быстрее всего). Экспортёр может вызвать ошибку, если не может предоставить такой непрерывный буфер. Если этот флаг не задан, форма будет *NULL*. |
| `PyBUF_C_CONTIGUOUS` `PyBUF_F_CONTIGUOUS` `PyBUF_ANY_CONTIGUOUS` | Эти флаги указывают, что возвращаемый буфер должен быть соответственно C-непрерывным (последнее измерение меняется быстрее всего), Fortran-непрерывным (первое измерение меняется быстрее всего) или любым из них. Все эти флаги подразумевают `PyBUF_STRIDES` и гарантируют, что структура информации о шагах будет заполнена корректно. |
| `PyBUF_INDIRECT` | Этот флаг указывает, что возвращаемый буфер должен содержать информацию suboffsets (может быть NULL, если suboffsets не нужны). Используется, когда потребитель может работать с косвенной адресацией массива, подразумеваемой этими suboffsets. Этот флаг подразумевает `PyBUF_STRIDES`. |
| `PyBUF_FORMAT` | Возвращаемый буфер должен содержать настоящую информацию о формате, если этот флаг указан. Это используется, когда потребитель собирается проверять, какой именно тип данных хранится. Экспортёр всегда должен быть способен предоставить эту информацию по запросу. Если формат явно не запрошен, он должен быть возвращён как *NULL* (что означает `'B'`, то есть беззнаковые байты). |
| `PyBUF_STRIDED` | Это эквивалентно `(PyBUF_STRIDES \| PyBUF_WRITABLE)`. |
| `PyBUF_STRIDED_RO` | Это эквивалентно `(PyBUF_STRIDES)`. |
| `PyBUF_RECORDS` | Это эквивалентно `(PyBUF_STRIDES \| PyBUF_FORMAT \| PyBUF_WRITABLE)`. |
| `PyBUF_RECORDS_RO` | Это эквивалентно `(PyBUF_STRIDES \| PyBUF_FORMAT)`. |
| `PyBUF_FULL` | Это эквивалентно `(PyBUF_INDIRECT \| PyBUF_FORMAT \| PyBUF_WRITABLE)`. |
| `` PyBUF_FULL_RO` `` | Это эквивалентно `(PyBUF_INDIRECT \| PyBUF_FORMAT)`. |
| `PyBUF_CONTIG` | Это эквивалентно `(PyBUF_ND \| PyBUF_WRITABLE)`. |
| `PyBUF_CONTIG_RO` | Это эквивалентно `(PyBUF_ND)`. |

**\[PyBuffer\_Release\]void `PyBuffer_Release`([PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*obj*, [Py\_buffer](https://python-all.ru/3.0/c-api/buffer.html#Py_buffer) *\*view*)**

Освобождает буфер

*view*

для объекта

*obj*

. Должен вызываться, когда буфер больше не используется, так как это может освободить память.

**\[PyBuffer\_SizeFromFormat\]Py\_ssize\_t `PyBuffer_SizeFromFormat`(const char *\**)**

Возвращает неявный

`~Py_buffer.itemsize`

из форматной строки struct

`~Py_buffer.format`

.

**\[PyObject\_CopyToObject\]int `PyObject_CopyToObject`([PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*obj*, void *\*buf*, Py\_ssize\_t *len*, char *fortran*)**

Копирует

*len*

байт данных, на которые указывает непрерывный блок памяти

*buf*

, в буфер, экспортируемый obj. Буфер, разумеется, должен быть доступен для записи. Возвращает 0 при успехе и -1 с вызовом ошибки при неудаче. Если у объекта нет буфера для записи, вызывается ошибка. Если

*fortran*

равен

`'F'`

, то в случае многомерного объекта данные копируются в массив в стиле Fortran (первое измерение меняется быстрее всего). Если

*fortran*

равен

`'C'`

, данные копируются в стиле C (последнее измерение меняется быстрее всего). Если

*fortran*

равен

`'A'`

, то разницы нет, и копирование выполняется наиболее эффективным способом.

**\[PyBuffer\_IsContiguous\]int `PyBuffer_IsContiguous`([Py\_buffer](https://python-all.ru/3.0/c-api/buffer.html#Py_buffer) *\*view*, char *fortran*)**

Возвращает 1, если память, определяемая

*view*

, является смежной в стиле C (

*fortran*

равно

`'C'`

) или в стиле Fortran (

*fortran*

равно

`'F'`

), или любого из них (

*fortran*

равно

`'A'`

). В противном случае возвращает 0.

**\[PyBuffer\_FillContiguousStrides\]void `PyBuffer_FillContiguousStrides`(int *ndim*, Py\_ssize\_t *\*shape*, Py\_ssize\_t *\*strides*, Py\_ssize\_t *itemsize*, char *fortran*)**

Заполняет массив

*strides*

байтовыми шагами непрерывного (в стиле C, если

*fortran*

равно

`'C'`

, или в стиле Фортрана, если

*fortran*

равно

`'F'`

) массива заданной формы с заданным количеством байтов на элемент.

**\[PyBuffer\_FillInfo\]int `PyBuffer_FillInfo`([Py\_buffer](https://python-all.ru/3.0/c-api/buffer.html#Py_buffer) *\*view*, void *\*buf*, Py\_ssize\_t *len*, int *readonly*, int *infoflags*)**

Заполняет структуру буферной информации

*view*

корректно для экспортёра, который может передавать только смежный блок памяти из «unsigned bytes» заданной длины. Возвращает 0 при успехе и -1 (с порождением исключения) при ошибке.

## Объекты MemoryView

Объект memoryview – это расширенный буферный объект, который может заменить буферный объект (но не обязан, так как тот может оставаться простым одномерным объектом memoryview объект). Он, в отличие от [`Py_buffer`](https://python-all.ru/3.0/c-api/buffer.html#Py_buffer), является объектом Python (предоставляется как [`memoryview`](https://python-all.ru/3.0/library/stdtypes.html#memoryview) в [`builtins`](https://python-all.ru/3.0/library/builtins.html#module-builtins)), поэтому его можно использовать в коде Python.

**\[PyMemoryView\_FromObject\][PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject)\* `PyMemoryView_FromObject`([PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*obj*)**

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