Skip to content

memoryview() Function Complexity

The memoryview() function creates memory views of bytes-like objects without copying.

Complexity Analysis

Case Time Space Notes
Create memoryview O(1) O(1) Just view, no copy of underlying data
Index access O(1) O(1) Direct memory access
Slicing O(1) O(1) Creates new view object, no data copy
bytes(mv) conversion O(n) O(n) n = view size; copies data
Modification O(1) O(1) Only if underlying buffer is mutable (e.g., bytearray)

Basic Usage

From Bytes

# O(1) - create view, no copy
b = b"hello"
mv = memoryview(b)
# <memory at 0x...>

# Access elements
mv[0]      # 104 (ord('h'))
mv[1:3]    # <memory at 0x...> - slice is also O(1) view

From Bytearray

# O(1) - create view
ba = bytearray(b"hello")
mv = memoryview(ba)

# Can modify through view
mv[0] = 72  # O(1) - changes 'h' to 'H'
print(ba)   # bytearray(b'Hello')

From Array

# O(1) - works with array module
import array

arr = array.array('i', [1, 2, 3, 4, 5])
mv = memoryview(arr)

# Access as view
mv[0]  # 1

Complexity Details

No Copying

# O(1) - memoryview doesn't copy data
b = b"a" * 10000
mv = memoryview(b)  # O(1) - instant, no copy

# vs creating a list copy
lst = list(b)  # O(n) - creates list

# View uses original memory

Slicing

# O(1) - slice is just another view
b = b"hello world"
mv = memoryview(b)

# Original view
mv[0]      # 104

# Slice - also O(1), doesn't copy
slice_view = mv[6:11]  # <memory at 0x...> - "world"

# Can modify through slice (if writable)

Indexing

# O(1) - direct memory access
mv = memoryview(b"test")

# Read element
byte_val = mv[0]  # 116

# Write element (if mutable)
ba = bytearray(b"test")
mv = memoryview(ba)
mv[0] = 84  # O(1) - changes to 'T'

Common Patterns

Zero-Copy Data Access

# O(1) - no memory copy
data = bytearray(b"binary data here")
view = memoryview(data)  # O(1)

# Process without copying
def process(view):
    for i in range(len(view)):
        print(view[i])

process(view)  # Efficient - no copy

Efficient Binary Protocol

# O(1) - parse binary data without copying
binary_data = b"\x01\x02\x03\x04"
view = memoryview(binary_data)

# Parse header - O(1)
header_type = view[0]   # 1
header_version = view[1] # 2

# Parse payload - O(1) slice
payload = view[2:4]  # <memory>

Memory Mapping

# O(1) - create view of mutable buffer
buffer = bytearray(1024)
view = memoryview(buffer)

# Modify through view
view[0:4] = b"HEAD"  # O(4) - copy 4 bytes

# Read back
header = bytes(view[0:4])  # O(4) to convert to bytes

Efficient Data Transfer

# O(1) - pass view instead of copying
def send_data(view):
    # view is O(1) to create, no memory allocation
    # Copy only when actually sending
    bytes_to_send = bytes(view)  # O(n)
    # network.send(bytes_to_send)

data = b"large data" * 1000
view = memoryview(data)  # O(1) - instant
# send_data(view)  # Efficient

Performance Patterns

vs Copying

# Inefficient - copying
data = b"x" * 10**6
copy = data[100:200]  # O(100) - creates new bytes

# Efficient - memoryview
view = memoryview(data)  # O(1)
slice_view = view[100:200]  # O(1) - just a view

vs List Conversion

# List conversion - O(n)
b = b"hello"
lst = list(b)  # O(5) - [104, 101, 108, 108, 111]

# Memoryview - O(1)
mv = memoryview(b)  # O(1)
mv[0]  # 104

Batch Processing

# O(n) - process without copying
def process_chunks(data):
    mv = memoryview(data)  # O(1)

    # Process in chunks - O(n) total
    for i in range(0, len(mv), 1024):
        chunk = mv[i:i+1024]  # O(1) per chunk - just view
        process_chunk(chunk)  # Process view

data = b"x" * 1000000
process_chunks(data)  # Efficient - no copies

Practical Examples

Binary File Processing

# O(1) - create view of file data
with open("large.bin", "rb") as f:
    data = f.read()

mv = memoryview(data)  # O(1)

# Access header without copying
magic = bytes(mv[0:4])  # O(4) - only copy what needed
version = mv[4]  # O(1)

# Process payload - O(1) view creation
payload = mv[16:]  # O(1)

Image Data Manipulation

# O(1) - view image pixels
from PIL import Image

img = Image.open("photo.png")
img_bytes = img.tobytes()  # Get raw pixel data

mv = memoryview(img_bytes)  # O(1) view

# Access pixel - O(1)
pixel_r = mv[0]  # Red component
pixel_g = mv[1]  # Green component
pixel_b = mv[2]  # Blue component

Network Protocol Parser

# O(1) - parse protocol messages
def parse_header(data):
    view = memoryview(data)  # O(1)

    # Extract fields - all O(1)
    msg_type = view[0]
    length = int.from_bytes(view[1:3], 'big')
    flags = view[3]

    return {
        'type': msg_type,
        'length': length,
        'flags': flags
    }

packet = b"\x01\x00\x10\xFF" + b"payload..."
header = parse_header(packet)

Efficient Buffer Sharing

# O(1) - share buffer without copying
def fill_buffer(view, value):
    for i in range(len(view)):
        view[i] = value

buffer = bytearray(1000)
view = memoryview(buffer)  # O(1)

fill_buffer(view, 0)  # Fill with zeros - O(1000)
# buffer is now filled

Edge Cases

Empty Memoryview

# O(1)
mv = memoryview(b"")   # <memory at 0x...>
len(mv)  # 0

Single Byte

# O(1)
mv = memoryview(b"a")
mv[0]  # 97

Immutable View

# O(1) - view of bytes (immutable)
mv = memoryview(b"hello")

# Cannot modify
# mv[0] = 72  # TypeError - read-only buffer

# But can create view

Mutable View

# O(1) - view of bytearray (mutable)
ba = bytearray(b"hello")
mv = memoryview(ba)

# Can modify
mv[0] = 72  # O(1) - 'H'
print(ba)   # bytearray(b'Hello')

Memory Sharing

# O(1) - modifications visible in original
ba = bytearray(b"test")
mv = memoryview(ba)

# Modify through view
mv[0] = 84  # 'T'

# Changes visible in original
print(ba)   # bytearray(b'Test')

# Changes also visible in view
print(mv[0])  # 84

Conversion Operations

# O(n) - convert memoryview to bytes
data = b"hello"
mv = memoryview(data)

# Convert to bytes
b = bytes(mv)  # O(5) - creates copy
# b'hello'

# Convert to list
lst = list(mv)  # O(5)
# [104, 101, 108, 108, 111]

Limitations

# O(1) - fast, but limited flexibility
mv = memoryview(b"hello")

# Can't concatenate directly
# mv + mv  # TypeError

# Must convert to bytes first
result = bytes(mv) + bytes(mv)  # O(2n)

# Can't append
# mv.append(33)  # AttributeError

Best Practices

Do:

  • Use memoryview for zero-copy access
  • Create memoryview to pass to functions efficiently
  • Use slicing for efficient sub-ranges
  • Convert to bytes only when necessary

Avoid:

  • Using memoryview for single access (overhead not worth it)
  • Assuming memoryview works like list (different API)
  • Trying to modify immutable buffers (bytes)
  • Creating memoryview of very small data

Version Notes

  • Python 2.x: memoryview() available (added in 2.7)
  • Python 3.x: Improved memoryview with slicing
  • All versions: Zero-copy view of bytes-like objects