Python memoryview()

Before we get into what memory views are, we need to first understand about Python's buffer protocol.


Python Buffer Protocol

The buffer protocol provides a way to access the internal data of an object. This internal data is a memory array or a buffer.

The buffer protocol allows one object to expose its internal data (buffers) and the other to access those buffers without intermediate copying.

This protocol is only accessible to us at the C-API level and not using our normal codebase.

So, in order to expose the same protocol to the normal Python codebase, memory views are present.


What is a memory view?

A memory view is a safe way to expose the buffer protocol in Python.

It allows you to access the internal buffers of an object by creating a memory view object.


Why buffer protocol and memory views are important?

We need to remember that whenever we perform some action on an object (call a function of an object, slice an array), Python needs to create a copy of the object.

If we have large data to work with (eg. binary data of an image), we would unnecessarily create copies of huge chunks of data, which serves almost no use.

Using the buffer protocol, we can give another object access to use/modify the large data without copying it. This makes the program use less memory and increases the execution speed.


Python memoryview() Syntax

To expose the buffer protocol using memoryview(), we use this syntax:

memoryview(obj)

memoryview() Parameters

The memoryview() function takes a single parameter:

  • obj - object whose internal data is to be exposed. obj must support the buffer protocol (bytes, bytearray)

Return value from memoryview()

The memoryview() function returns a memory view object.


Example 1: How memoryview() works in Python?

#random bytearray
random_byte_array = bytearray('ABC', 'utf-8')

mv = memoryview(random_byte_array)

# access memory view's zeroth index
print(mv[0])

# create byte from memory view
print(bytes(mv[0:2]))

# create list from memory view
print(list(mv[0:3]))

Output

65
b'AB'
[65, 66, 67]

Here, we created a memory view object mv from the byte array random_byte_array.

Then, we accessed the mv's 0th index, 'A', and printed it (which gives the ASCII value - 65).

Again, we accessed the mv's indices from 0 and 1, 'AB' , and converted them into bytes.

Finally, we accessed all indices of mv and converted it to a list. Since internally bytearray stores ASCII value for the alphabets, the output is a list of ASCII values of A, B, and C.


Example 2: Modify internal data using memory view

# random bytearray
random_byte_array = bytearray('ABC', 'utf-8')
print('Before updation:', random_byte_array)

mv = memoryview(random_byte_array)

# update 1st index of mv to Z
mv[1] = 90
print('After updation:', random_byte_array)

Output

Before updation: bytearray(b'ABC')
After updation: bytearray(b'AZC')

Here, we updated the memory view's 1st index to 90, the ASCII value of Z.

Since, the memory view object mv references the same buffer/memory, updating the index in mv also updates random_byte_array.

Did you find this article helpful?