Использование функции memoryview() в Python обеспечивает прямой доступ для чтения и записи к байтовым данным объекта без необходимости их предварительного копирования.
Что такое memoryview() в Python?
memoryview в Python — это встроенный объект, который позволяет коду получать доступ к внутренним данным объекта, поддерживающего протокол буфера, без копирования. Прежде чем мы углубимся в представление памяти, нам сначала нужно понять буферный протокол в Python.

Буферный протокол Python
Это протокол, обеспечивающий доступ к внутренним данным объекта. Внутренние данные могут быть массивом памяти или буфером. Этот протокол позволяет одному объекту предоставлять свои данные другим объектам, а другие объекты получают доступ к этим данным(буферу) без промежуточного копирования.
Но проблема в том, что если мы не можем получить доступ к этому протоколу со стандартной кодовой базой, это доступно нам на уровне C-API. Итак, в python, если мы хотим предоставить тот же протокол в python, нам нужно использовать memoryview.
Что такое memory view
Представление памяти — это безопасный способ раскрыть этот буферный протокол. Он позволяет нам получить доступ к внутренним буферам объекта, создав объект memory view в Python.
Синтаксис
|
1 |
memoryview(obj) |
Здесь obj — это внутренние данные, которые нужно показать. Но он должен поддерживать буферный протокол.
Возвращаемое значение
Функция memoryview() возвращает объект представления памяти данного объекта.
См. следующий пример кода.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# app.py # Creating a random byte array rarray = bytearray('XYZ', 'utf-8') # getting memory view mview = memoryview(rarray) # Printing memory view's 0th index print(mview[0]) # Now create a list of memory view print(list(mview[0:3])) # Create one tuple of memory view print(tuple(mview[0:3])) |
Смотрите вывод.
|
1 2 |
88 [88, 89, 90](88, 89, 90) |
Теперь мы увидим, как мы можем изменить внутренние данные с помощью memoryview.
См. второй пример.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# app.py # This program will show how we can # Modify internal data using Memory View # Creating a byte array rarray = bytearray('ABC', 'utf-8') # Printing the array before update print(rarray) # Creating memory view mv = memoryview(rarray) # Now we will update one value of Memory View mv[2] = 70 # Now printing updated Byte Array print(rarray) |
Вывод:
|
1 2 |
bytearray(b'ABC') bytearray(b'ABF') |
В приведенной выше программе сначала мы создаем массив байтов.
Затем мы создаем memory view и обновляем представление памяти, а теперь снова печатаем массив, чтобы увидеть разницу.
Почему buffer protocol и memoryview так важны?
Представления памяти Python полезны тем, что их можно нарезать без копирования базовых данных, в отличие от bytes/str.
Кроме того, следует помнить, что всякий раз, когда мы выполняем какое-либо действие над объектом (вызываем функцию объекта, разрезаем массив), нам (или Python) необходимо создать копию объекта.
Если у нас есть большие данные для работы (например, двоичные данные изображения), мы будем без необходимости создавать копии огромных кусков данных, которые практически бесполезны.
Используя протокол буфера, мы можем предоставить другому объекту доступ для использования/изменения больших данных без их копирования. Это позволяет программе использовать меньше памяти и увеличивает скорость выполнения.
Объекты memoryview отлично подходят, когда вам нужны подмножества двоичных данных, которые должны поддерживать только индексацию. Вместо того, чтобы брать фрагменты (и создавать новые, потенциально большие) объекты для передачи другому API, вы можете взять объект memoryview. Одним из таких примеров API может быть модуль struct.
Вместо того, чтобы передавать срез объекта больших байтов для анализа упакованных значений C, вы передаете представление памяти только той области, из которой вам нужно извлечь значения.
Объекты memoryview фактически изначально поддерживают распаковку структуры; вы можете нацелить область базового объекта байтов с помощью среза, а затем использовать .cast() для «интерпретации» базовых байтов как длинных целых чисел, значений с плавающей запятой или n-мерных списков целых чисел.
Это обеспечивает очень эффективную интерпретацию формата двоичного файла без необходимости создания дополнительных копий байтов.
