The memoryview
object in MicroPython provides a way to access the memory of other binary objects without copying the data. This is particularly useful for working with large amounts of data in embedded systems where memory is limited.
With memoryview
, you can access and modify parts of data structures like bytes, bytearrays, or other buffers efficiently.
This tutorial will cover the basics of memoryview
in MicroPython, including how to create and use memoryview
objects, modify data, and work with slices.
Table of Contents:
1. What is a memoryview?
A memoryview object in MicroPython allows you to work directly with the memory of binary data structures like bytes and bytearray without making a copy of the data.
This helps in saving memory and improving performance, especially when dealing with large binary data.
2. Creating a memoryview
You can create a memoryview object by passing a bytes-like object (e.g., bytes, bytearray) to the memoryview() constructor.
Example: Creating a memoryview
data = bytearray(b'Hello, MicroPython!') mem_view = memoryview(data) print(mem_view) # Output:
In this example, a memoryview object is created for a bytearray. Note that the memoryview provides a window into the existing memory of the bytearray, not a copy of it.
3. Accessing Data with memoryview
You can access elements in a memoryview object using indexing, similar to how you would with lists or arrays.
Example: Accessing Elements
data = bytearray(b'Hello, MicroPython!') mem_view = memoryview(data) # Access individual elements print(mem_view[0]) # Output: 72 (ASCII code for 'H') print(mem_view[7]) # Output: 77 (ASCII code for 'M') # Convert to a list to see all elements print(list(mem_view)) # Output: [72, 101, 108, 108, 111, 44, 32, 77, 105, 99, 114, 111, 80, 121, 116, 104, 111, 110, 33]
Explanation:
mem_view[0] gives the byte value of the first element in the bytearray. In this case, 72 is the ASCII code for ‘H’.
4. Modifying Data with memoryview
One of the key advantages of using a memoryview is that you can modify the data of the original object it points to, as long as the underlying object is mutable (e.g., bytearray).
Example: Modifying Data
data = bytearray(b'Hello, MicroPython!') mem_view = memoryview(data) # Modify the memoryview (changes will reflect in the original bytearray) mem_view[0] = ord('h') mem_view[7] = ord('m') print(data) # Output: bytearray(b'hello, microPython!')
Explanation:
mem_view[0] = ord(‘h’) changes the first byte to the ASCII value of ‘h’.
The changes are reflected in the original bytearray because the memoryview directly modifies its memory.
5. Slicing with memoryview
A memoryview object supports slicing, allowing you to create sub-views of the original data without copying it.
Example: Slicing a memoryview
data = bytearray(b'Hello, MicroPython!') mem_view = memoryview(data) # Slice the memoryview to get a sub-view sub_view = mem_view[7:17] # Access elements in the sliced view print(bytes(sub_view)) # Output: b'MicroPytho'
Explanation:
mem_view[7:17] creates a memoryview slice of the original data, giving a window into the bytes from index 7 to 16.
Using bytes(sub_view) converts the sliced memoryview back into a bytes object for display.
6. Practical Examples
Example 1: Modifying Specific Data Segments
Suppose you have a large bytearray, and you want to modify only a specific segment of it. With memoryview, you can access and modify that segment directly.
data = bytearray(b'This is a long data segment...') mem_view = memoryview(data) # Modify a specific segment using a memoryview mem_view[8:12] = b'Short' print(data) # Output: bytearray(b'This is a Short data segment...')
Explanation:
mem_view[8:12] = b’Short’ modifies the segment from index 8 to 11, replacing it with ‘Short’.
Example 2: Working with Binary Data
When dealing with binary protocols or hardware communication, you often work with fixed-length data. memoryview makes it easy to extract and manipulate parts of such binary data efficiently.
# Simulate binary data (e.g., sensor data stream) sensor_data = bytearray(b'\x01\x02\x03\x04\x05\x06\x07\x08') # Create a memoryview to parse the data mem_view = memoryview(sensor_data) # Extract the first four bytes as an identifier identifier = mem_view[:4] print(list(identifier)) # Output: [1, 2, 3, 4] # Modify a specific byte (e.g., change sensor status) mem_view[4] = 0x09 print(sensor_data) # Output: bytearray(b'\x01\x02\x03\x04\t\x06\x07\x08')
Explanation:
The memoryview allows direct access and modification of binary data in the bytearray, making it easy to parse and update values.
Example 3: Copying Data Efficiently
Sometimes, you may want to copy part of the data from a memoryview into another bytearray or similar structure.
data = bytearray(b'1234567890') mem_view = memoryview(data) # Create a new bytearray to store a copy of the sliced data copy_data = bytearray(5) copy_data[:] = mem_view[5:] print(copy_data) # Output: bytearray(b'67890')
Explanation:
The sliced memoryview[5:] is copied into copy_data using slicing, providing an efficient way to extract and store data.
Conclusion
The memoryview object in MicroPython provides an efficient way to work with binary data, especially when memory and processing power are limited. It allows you to:
Access and modify binary data directly without copying it.
Work with slices of data efficiently.
Perform operations on segments of large data structures.
Key points to remember:
memoryview operates directly on the memory of bytes-like objects (bytearray, bytes), avoiding unnecessary copying.
It can be used to modify the original data if the underlying object is mutable (e.g., bytearray).
Slicing a memoryview creates a new memoryview object pointing to the specified part of the original data.
By understanding how to use memoryview objects, you can optimize data processing in your MicroPython applications, particularly when dealing with binary protocols, large data segments, or hardware interfaces.