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

---

# Протокол буфера

Некоторые объекты в Python предоставляют доступ к лежащему в основе массиву памяти или *буферу*. К таким объектам относятся встроенные [`bytes`](https://python-all.ru/3.4/library/functions.html#bytes) и [`bytearray`](https://python-all.ru/3.4/library/functions.html#bytearray), а также некоторые типы расширений, например [`array.array`](https://python-all.ru/3.4/library/array.html#array.array). Сторонние библиотеки могут определять собственные типы для специальных целей, таких как обработка изображений или численный анализ.

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

Python предоставляет такую возможность на уровне C в виде [*буферного протокола*](https://python-all.ru/3.4/c-api/buffer.html#bufferobjects). У этого протокола есть две стороны:

- На стороне производителя тип может экспортировать «буферный интерфейс», который позволяет объектам этого типа предоставлять информацию о своём базовом буфере. Этот интерфейс описан в разделе [*Buffer Object Structures*](https://python-all.ru/3.4/c-api/typeobj.html#buffer-structs);
- На стороне потребителя доступно несколько способов получить указатель на необработанные базовые данные объекта (например, параметр метода).

Простые объекты, такие как [`bytes`](https://python-all.ru/3.4/library/functions.html#bytes) и [`bytearray`](https://python-all.ru/3.4/library/functions.html#bytearray), предоставляют свой базовый буфер в байт-ориентированной форме. Возможны и другие формы; например, элементы, предоставляемые [`array.array`](https://python-all.ru/3.4/library/array.html#array.array), могут быть многобайтовыми значениями.

Примером потребителя интерфейса буфера является метод [`write()`](https://python-all.ru/3.4/library/io.html#io.BufferedIOBase.write) файловых объектов: любой объект, способный экспортировать последовательность байтов через интерфейс буфера, может быть записан в файл. В то время как `write()` требует только доступа на чтение к внутреннему содержимому переданного ему объекта, другие методы, такие как [`readinto()`](https://python-all.ru/3.4/library/io.html#io.BufferedIOBase.readinto), требуют доступа на запись к содержимому своего аргумента. Интерфейс буфера позволяет объектам выборочно разрешать или запрещать экспорт буферов для чтения-записи и только для чтения.

Существует два способа для потребителя буферного интерфейса получить буфер над целевым объектом:

- вызов [`PyObject_GetBuffer()`](https://python-all.ru/3.4/c-api/buffer.html#c.PyObject_GetBuffer) с правильными параметрами;
- вызов [`PyArg_ParseTuple()`](https://python-all.ru/3.4/c-api/arg.html#c.PyArg_ParseTuple) (или одной из его разновидностей) с одним из `y*`, `w*` или `s*` [*кодов формата*](https://python-all.ru/3.4/c-api/arg.html#arg-parsing).

В обоих случаях [`PyBuffer_Release()`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBuffer_Release) необходимо вызвать, когда буфер больше не нужен. Несоблюдение этого может привести к различным проблемам, таким как утечка ресурсов.

## Структура буфера

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

В отличие от большинства типов данных, предоставляемых интерпретатором Python, буферы не являются указателями на [`PyObject`](https://python-all.ru/3.4/c-api/structures.html#c.PyObject), а представляют собой простые структуры C. Это позволяет создавать и копировать их очень просто. Когда требуется универсальная обёртка вокруг буфера, можно создать объект [*memoryview*](https://python-all.ru/3.4/c-api/memoryview.html#memoryview-objects).

Краткие инструкции по написанию экспортирующего объекта см. в разделе [*Структуры объектов буфера*](https://python-all.ru/3.4/c-api/typeobj.html#buffer-structs). Для получения буфера см. [`PyObject_GetBuffer()`](https://python-all.ru/3.4/c-api/buffer.html#c.PyObject_GetBuffer).

**`Py_buffer`**

**void \*`buf`**

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

Для непрерывных массивов значение указывает на начало блока памяти.

**void \*`obj`**

Новая ссылка на экспортирующий объект. Ссылка принадлежит потребителю и автоматически уменьшается на единицу и устанавливается в *NULL* функцией [`PyBuffer_Release()`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBuffer_Release). Это поле эквивалентно возвращаемому значению любой стандартной функции C-API.

В особом случае для *временных* буферов, которые обёрнуты функциями [`PyMemoryView_FromBuffer()`](https://python-all.ru/3.4/c-api/memoryview.html#c.PyMemoryView_FromBuffer) или [`PyBuffer_FillInfo()`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBuffer_FillInfo), это поле равно *NULL*. В общем случае экспортирующие объекты НЕ ДОЛЖНЫ использовать эту схему.

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

`product(shape) * itemsize`. Для непрерывных массивов это длина базового блока памяти. Для несплошных массивов это длина, которую имела бы логическая структура, если бы она была скопирована в непрерывное представление.

Доступ к `((char *)buf)[0] до ((char *)buf)[len-1]` действителен только в том случае, если буфер был получен с помощью запроса, гарантирующего непрерывность. В большинстве случаев такой запрос будет [`PyBUF_SIMPLE`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_SIMPLE) или [`PyBUF_WRITABLE`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_WRITABLE).

**int `readonly`**

Индикатор того, является ли буфер доступным только для чтения. Это поле управляется флагом [`PyBUF_WRITABLE`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_WRITABLE).

**Py\_ssize\_t `itemsize`**

Размер одного элемента в байтах. То же, что значение [`struct.calcsize()`](https://python-all.ru/3.4/library/struct.html#struct.calcsize), вызванной для значений [`format`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.format), не равных NULL.

Важное исключение: если потребитель запрашивает буфер без флага [`PyBUF_FORMAT`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_FORMAT), [`format`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.format) будет установлен в *NULL*, но [`itemsize`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.itemsize) по-прежнему содержит значение исходного формата.

Если [`shape`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.shape) присутствует, равенство `product(shape) * itemsize == len` по-прежнему выполняется, и потребитель может использовать [`itemsize`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.itemsize) для навигации по буферу.

Если [`shape`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.shape) равен *NULL* в результате запроса [`PyBUF_SIMPLE`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_SIMPLE) или [`PyBUF_WRITABLE`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_WRITABLE), потребитель должен игнорировать [`itemsize`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.itemsize) и считать `itemsize == 1`.

**const char \*`format`**

Строка, завершающаяся *NUL*, в синтаксисе стиля модуля [`struct`](https://python-all.ru/3.4/library/struct.html#module-struct), описывающая содержимое одного элемента. Если это *NULL*, предполагается `"B"` (беззнаковые байты).

Это поле управляется флагом [`PyBUF_FORMAT`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_FORMAT).

**int `ndim`**

Количество измерений, которое память представляет в виде n-мерного массива. Если оно равно 0, [`buf`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.buf) указывает на единственный элемент, представляющий скаляр. В этом случае [`shape`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.shape), [`strides`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.strides) и [`suboffsets`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.suboffsets) ДОЛЖНЫ быть *NULL*.

Макрос `PyBUF_MAX_NDIM` ограничивает максимальное количество измерений до 64. Экспортёры ДОЛЖНЫ соблюдать это ограничение, потребители многомерных буферов должны быть способны обрабатывать до `PyBUF_MAX_NDIM` измерений.

**Py\_ssize\_t \*`shape`**

Массив из `Py_ssize_t` длиной [`ndim`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.ndim), описывающий форму памяти как n-мерный массив. Обратите внимание, что `shape[0] * ... * shape[ndim-1] * itemsize` ДОЛЖНО быть равно [`len`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.len).

Значения shape ограничены `shape[n] >= 0`. Случай `shape[n] == 0` требует особого внимания. См. [complex arrays](https://python-all.ru/3.4/c-api/buffer.html#complex-arrays) для получения дополнительной информации.

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

**Py\_ssize\_t \*`strides`**

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

Значения шага могут быть любым целым числом. Для обычных массивов шаги обычно положительны, но потребитель ДОЛЖЕН уметь обрабатывать случай `strides[n] <= 0`. См. [сложные массивы](https://python-all.ru/3.4/c-api/buffer.html#complex-arrays) для получения дополнительной информации.

Массив шагов доступен потребителю только для чтения.

**Py\_ssize\_t \*`suboffsets`**

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

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

Такой тип представления массива используется библиотекой Python Imaging Library (PIL). Дополнительную информацию о доступе к элементам такого массива см. в разделе [сложные массивы](https://python-all.ru/3.4/c-api/buffer.html#complex-arrays).

Массив смещений подмассивов доступен потребителю только для чтения.

**void \*`internal`**

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

## Типы запросов буфера

Буферы обычно получают, отправляя запрос на буфер экспортирующему объекту через [`PyObject_GetBuffer()`](https://python-all.ru/3.4/c-api/buffer.html#c.PyObject_GetBuffer). Поскольку сложность логической структуры памяти может сильно различаться, потребитель использует аргумент *flags* для указания точного типа буфера, который он может обработать.

Все поля [`Py_buffer`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer) однозначно определяются типом запроса.

### поля, не зависящие от запроса

Следующие поля не зависят от *flags* и должны всегда заполняться корректными значениями: [`obj`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.obj), [`buf`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.buf), [`len`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.len), [`itemsize`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.itemsize), [`ndim`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.ndim).

### только для чтения, формат

> **`PyBUF_WRITABLE`**
>
> Управляет полем [`readonly`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.readonly). Если установлен, экспортёр ДОЛЖЕН предоставить буфер для записи, иначе сообщить об ошибке. В противном случае экспортёр МОЖЕТ предоставить либо буфер только для чтения, либо для записи, но выбор ДОЛЖЕН быть согласован для всех потребителей.
>
> **`PyBUF_FORMAT`**
>
> Управляет полем [`format`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.format). Если установлен, это поле ДОЛЖНО быть заполнено корректно. В противном случае это поле ДОЛЖНО быть *NULL*.

[`PyBUF_WRITABLE`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_WRITABLE) может быть объединён операцией | с любыми флагами из следующего раздела. Поскольку [`PyBUF_SIMPLE`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_SIMPLE) определён как 0, [`PyBUF_WRITABLE`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_WRITABLE) может использоваться как самостоятельный флаг для запроса простого буфера для записи.

[`PyBUF_FORMAT`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_FORMAT) может быть объединён операцией | с любыми флагами, кроме [`PyBUF_SIMPLE`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_SIMPLE). Последний уже подразумевает формат `B` (беззнаковые байты).

### форма, шаги, подсмещения

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

| Запрос | форма | шаги | подсмещения |
| --- | --- | --- | --- |
| `PyBUF_INDIRECT` | да | да | если необходимо |
| `PyBUF_STRIDES` | да | да | NULL |
| `PyBUF_ND` | да | NULL | NULL |
| `PyBUF_SIMPLE` | NULL | NULL | NULL |

### запросы непрерывности

Непрерывность по C или Fortran может быть явно запрошена, с информацией о шагах или без неё. Без информации о шагах буфер должен быть непрерывным по C.

| Запрос | форма | шаги | подсмещения | непрерывность |
| --- | --- | --- | --- | --- |
| `PyBUF_C_CONTIGUOUS` | да | да | NULL | C |
| `PyBUF_F_CONTIGUOUS` | да | да | NULL | F |
| `PyBUF_ANY_CONTIGUOUS` | да | да | NULL | C или F |
| `PyBUF_ND` | да | NULL | NULL | C |

### составные запросы

Все возможные запросы полностью определяются некоторой комбинацией флагов из предыдущего раздела. Для удобства протокол буфера предоставляет часто используемые комбинации в виде отдельных флагов.

В следующей таблице *U* означает неопределённую смежность. Потребитель должен вызвать [`PyBuffer_IsContiguous()`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBuffer_IsContiguous), чтобы определить смежность.

| Запрос | форма | шаги | подсмещения | непрерывность | только для чтения | формат |
| --- | --- | --- | --- | --- | --- | --- |
| `PyBUF_FULL` | да | да | если необходимо | U | 0 | да |
| `PyBUF_FULL_RO` | да | да | если необходимо | U | 1 или 0 | да |
| `PyBUF_RECORDS` | да | да | NULL | U | 0 | да |
| `PyBUF_RECORDS_RO` | да | да | NULL | U | 1 или 0 | да |
| `PyBUF_STRIDED` | да | да | NULL | U | 0 | NULL |
| `PyBUF_STRIDED_RO` | да | да | NULL | U | 1 или 0 | NULL |
| `PyBUF_CONTIG` | да | NULL | NULL | C | 0 | NULL |
| `PyBUF_CONTIG_RO` | да | NULL | NULL | C | 1 или 0 | NULL |

## Комплексные массивы

### В стиле NumPy: форма и шаги

Логическая структура массивов в стиле NumPy определяется [`itemsize`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.itemsize), [`ndim`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.ndim), [`shape`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.shape) и [`strides`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.strides).

Если `ndim == 0`, то область памяти, на которую указывает [`buf`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.buf), интерпретируется как скаляр размера [`itemsize`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.itemsize). В таком случае и [`shape`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.shape), и [`strides`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.strides) равны *NULL*.

Если [`strides`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.strides) равна *NULL*, массив интерпретируется как стандартный n-мерный C-массив. В противном случае потребитель должен обращаться к n-мерному массиву следующим образом:

> `ptr = (char *)buf + indices[0] * strides[0] + ... + indices[n-1] * strides[n-1]`
>
> `item = *((typeof(item) *)ptr);`

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

```python
def verify_structure(memlen, itemsize, ndim, shape, strides, offset):
    """Проверить, что параметры представляют допустимый массив в пределах
       границ выделенной памяти:
           char *mem: начало физического блока памяти
           memlen: длина физического блока памяти
           смещение: (char *)buf - mem
    """
    if offset % itemsize:
        return False
    if offset < 0 or offset+itemsize > memlen:
        return False
    if any(v % itemsize for v in strides):
        return False

    if ndim <= 0:
        return ndim == 0 and not shape and not strides
    if 0 in shape:
        return True

    imin = sum(strides[j]*(shape[j]-1) for j in range(ndim)
               if strides[j] <= 0)
    imax = sum(strides[j]*(shape[j]-1) for j in range(ndim)
               if strides[j] > 0)

    return 0 <= offset+imin and offset+imax+itemsize <= memlen
```

### В стиле PIL: форма, шаги и suboffsets

В дополнение к обычным элементам, массивы в стиле PIL могут содержать указатели, по которым нужно перейти, чтобы добраться до следующего элемента в измерении. Например, обычный трёхмерный C-массив `char v[2][2][3]` также можно рассматривать как массив из 2 указателей на 2 двумерных массива: `char (*v[2])[2][3]`. В представлении со смещениями подмассивов эти два указателя могут быть встроены в начало [`buf`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.buf), указывая на два массива `char x[2][3]`, которые могут располагаться в любом месте памяти.

Ниже приведена функция, возвращающая указатель на элемент в 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;
}
```

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

#### `int PyObject_CheckBuffer(PyObject *obj)`

Возвращает 1, если *obj* поддерживает интерфейс буфера, иначе 0. Если возвращается 1, это не гарантирует, что [`PyObject_GetBuffer()`](https://python-all.ru/3.4/c-api/buffer.html#c.PyObject_GetBuffer) выполнится успешно.

#### `int PyObject_GetBuffer(PyObject *exporter, Py_buffer *view, int flags)`

Отправляет запрос *exporter* на заполнение *view* в соответствии с *flags*. Если экспортёр не может предоставить буфер точного типа, он ДОЛЖЕН вызвать исключение `PyExc_BufferError`, установить `view->obj` в *NULL* и вернуть -1.

При успехе заполняет *view*, устанавливает `view->obj` в новую ссылку на *exporter* и возвращает 0. В случае цепочечных поставщиков буферов, которые перенаправляют запросы одному объекту, `view->obj` МОЖЕТ ссылаться на этот объект вместо *exporter* (см. [*Структуры буферных объектов*](https://python-all.ru/3.4/c-api/typeobj.html#buffer-structs)).

Успешные вызовы [`PyObject_GetBuffer()`](https://python-all.ru/3.4/c-api/buffer.html#c.PyObject_GetBuffer) должны быть парными с вызовами [`PyBuffer_Release()`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBuffer_Release), аналогично `malloc()` и `free()`. Поэтому после того, как потребитель закончил работу с буфером, [`PyBuffer_Release()`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBuffer_Release) должен быть вызван ровно один раз.

#### `void PyBuffer_Release(Py_buffer *view)`

Освобождает буфер *view* и уменьшает счётчик ссылок для `view->obj`. Эта функция ДОЛЖНА быть вызвана, когда буфер больше не используется, иначе могут возникнуть утечки ссылок.

Вызов этой функции для буфера, который не был получен через [`PyObject_GetBuffer()`](https://python-all.ru/3.4/c-api/buffer.html#c.PyObject_GetBuffer), является ошибкой.

#### `Py_ssize_t PyBuffer_SizeFromFormat(const char *)`

Возвращает подразумеваемый [`itemsize`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.itemsize) из [`format`](https://python-all.ru/3.4/c-api/buffer.html#c.Py_buffer.format). Эта функция ещё не реализована.

#### `int PyBuffer_IsContiguous(Py_buffer *view, char order)`

Возвращает 1, если память, определённая *view*, является непрерывной в стиле C (*order* равен `'C'`) или в стиле Fortran (*order* равен `'F'`) или любым из них (*order* равен `'A'`). Иначе возвращает 0.

#### `void PyBuffer_FillContiguousStrides(int ndim, Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t itemsize, char order)`

Заполняет массив *strides* байтовыми шагами непрерывного (в стиле C, если *order* равен `'C'`, или в стиле Fortran, если *order* равен `'F'`) массива заданной формы с заданным числом байт на элемент.

#### `int PyBuffer_FillInfo(Py_buffer *view, PyObject *exporter, void *buf, Py_ssize_t len, int readonly, int flags)`

Обрабатывает запросы буфера для экспортёра, который хочет предоставить *buf* размером *len* с настройкой возможности записи в соответствии с *readonly*. *buf* интерпретируется как последовательность байтов без знака.

Аргумент *flags* указывает тип запроса. Эта функция всегда заполняет *view* в соответствии с flags, если только *buf* не был назначен только для чтения и в *flags* не установлен [`PyBUF_WRITABLE`](https://python-all.ru/3.4/c-api/buffer.html#c.PyBUF_WRITABLE).

При успехе устанавливает `view->obj` в новую ссылку на *exporter* и возвращает 0. В противном случае вызывает исключение `PyExc_BufferError`, устанавливает `view->obj` в *NULL* и возвращает -1;

Если эта функция используется как часть [*getbufferproc*](https://python-all.ru/3.4/c-api/typeobj.html#buffer-structs), *exporter* ДОЛЖЕН быть установлен на экспортирующий объект, а *flags* должны передаваться без изменений. В противном случае *exporter* ДОЛЖЕН быть NULL.
