Почему невозможно получить Py_buffer из объекта массива?

Документация Python по массиву четко заявляет, что массив соответствует интерфейсу буфера. Он даже предлагает не использовать метод buffer_info(). Но когда я пытаюсь получить Py_Buffer из кода C/C++ с помощью PyObject_GetBuffer() или использовать представление памяти python, я получаю ошибку.

Например, в Python (я использую версию 2.7):

>>> a = array.array('c')
>>> memoryview(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot make memory view because object does not have the buffer interface

Фактически, когда я выполняю поиск в кодовой базе python, только для bytearrayobject (bytearray), memoryobject (memoryview) и stringobject (str) устанавливается требуемый флаг Py_TPFLAGS_HAVE_NEWBUFFER. Насколько я понимаю, документация неверна; массив не поддерживает интерфейс буфера.

Я мог бы использовать bytearray, который поддерживает интерфейс буфера, проблема в том, что мне нужен практический метод fromfile() массива для чтения в буфере, который я могу использовать в своем коде C/C++.

Есть ли альтернатива, которая позволила бы мне прочитать файл в буфер и использовать этот буфер из кода C, а не задействовать копии памяти? (Я хочу обработать большие двоичные файлы, и копирование является менее желательным вариантом).

2 ответа

Решение

memoryview работает только с объектами, которые поддерживают буферный интерфейс Python 3. array.array в Python 3, но не в Python 2.7. Вы можете подать отчет об ошибке для этого. Просто используйте использование bytearray (или же str если вы используете его только для чтения). Обе поддержки memoryview просто хорошо.

Python 2.6+ имеет два разных буферных интерфейса, как и два разных типа классов: классическая версия и версия Python 3.

Из Справочного руководства по API Python/C:

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

В коде Python 2.7 вы можете работать с буферами старого стиля, используя buffer функция и буферы нового стиля с использованием memoryview, Python 3 поддерживает только последнее.

Аналогичное различие существует в Python 2 C API; PyObject_GetBuffer для нового интерфейса буфера, PyBuffer_FromObject/PyBuffer_FromReadWriteObject для старого интерфейса буфера (и должен работать для массивов). Смотрите ссылку выше для получения дополнительной информации.

Другие вопросы по тегам