memoryview.toreadonly()

Zero-copy defence. Share a large buffer with code you do not fully trust, without copying it and without letting that code write to it.

Memoryview methodPython 3.8+
Common call
safe = view.toreadonly()
Returns
memoryview — same bytes, writes rejected
Replaces
copying the buffer purely to stop someone modifying it
Watch out
it protects the VIEW, not the buffer — other writers still can
memoryview.toreadonly()
→ memoryview

Examples

1. Writes are rejected
ro = memoryview(bytearray(b'ab')).toreadonly() ro[0] = 99
Returns
TypeError: cannot modify read-only memory
2. Reading still works
ro.tolist()
Returns
[97, 98]
3. The flag
ro.readonly
Returns
True
4. Original unaffected
m = memoryview(bytearray(b'ab')) m.toreadonly() m.readonly
Returns
False
5. Already read-only
memoryview(b'ab').toreadonly().readonly
Returns
True
6. No copying
ro.nbytes
Returns
2 # same memory, not a duplicate

Pitfalls

1. It protects the view, not the buffer
The underlying bytearray is still mutable through any other reference. A read-only view stops the HOLDER of that view from writing; it does not freeze the data.
Data still changes
b = bytearray(b'ab')
ro = memoryview(b).toreadonly()
b[0] = 99
ro.tolist()
[99, 98] # changed underneath
Copy to freeze
frozen = bytes(memoryview(b))
an independent snapshot
2. The original view keeps write access
toreadonly returns a NEW view; it does not downgrade the one you called it on. Forgetting to use the returned object leaves the writable view in play.
Return value ignored
m.toreadonly()
m[0] = 99
succeeds — m was never restricted
Use what it returns
ro = m.toreadonly()
ro[0] = 99
TypeError
3. There is no way back
No toWritable exists. Once you hold only the read-only view, regaining write access means going back to the original buffer or view — so do not discard those if you will need to write later.
No reverse method
ro.towritable()
AttributeError: 'memoryview' object has no attribute 'towritable'
Keep the original
m = memoryview(b)
ro = m.toreadonly()   # keep m
m still writes
4. Python 3.8 and newer only
On older versions the method does not exist. The pre-3.8 way to hand out a non-writable view was to copy into bytes first, which costs the memory a view was meant to save.
Fails on 3.7
view.toreadonly()
AttributeError: 'memoryview' object has no attribute 'toreadonly'
Copy instead
memoryview(bytes(view))
read-only, but copies

When to use

Use it
  • Passing a large buffer to code that should only read it
  • Public APIs exposing internal buffers without copying
  • Enforcing an intent that a comment alone would not
Reach for something else
  • You need a genuine immutable snapshot → copy to bytes
  • The buffer is already immutable bytes — it is already read-only
  • Supporting Python 3.7 or older without a fallback

Notes

Complexity
O(1) — new view metadata, no data touched
Return
A new memoryview sharing the original memory
CPython impl
Objects/memoryobject.c :: memory_toreadonly
Memory
No copying; the new view keeps the buffer alive and exported
Thread-safe
Reading is safe; the source can still change under you via other references

FAQ

No — only that view. Anyone holding the original bytearray or a writable view can still change the bytes, and your read-only view will see the change. For a genuine snapshot you have to copy.

frozen = bytes(view)   # independent

History

3.8
memoryview.toreadonly added, giving a zero-copy way to share buffers safely.