memoryview.cast()

Changes how the bytes are read, never what they are. Reading four bytes as two 16-bit integers gives different numbers on a big-endian machine — the method uses NATIVE order and offers no way to choose.

Memoryview methodPython 3.3+
Common call
view.cast('H')
Returns
memoryview — same bytes, new element type
Replaces
struct.unpack, when you want a live view rather than a tuple
Watch out
native byte order only; results differ across architectures
memoryview.cast(format[, shape])
→ memoryview

Parameters

NameTypeRequiredDescription
formatstryesA single struct format character: 'B' unsigned byte, 'h'/'H' 16-bit, 'i'/'I' 32-bit, 'f' float, 'd' double, and so on.
shapelistno (None)Optional list of dimensions to reshape into. The total element count must match exactly.

Return value

memoryview — A new view over the SAME memory, with elements reinterpreted according to the format character. No data is copied or converted.

Examples

1. Bytes as 16-bit ints
memoryview(b'abcd').cast('H').tolist()
Returns
[25185, 25699] # little-endian
2. Back to bytes
view.cast('H').cast('B').tobytes()
Returns
b'abcd'
3. Element size changes
memoryview(b'abcd').cast('H').itemsize
Returns
2
4. Length changes too
len(memoryview(b'abcd').cast('H'))
Returns
2 # not 4
5. Reshape
memoryview(b'abcd').cast('B', [2, 2]).tolist()
Returns
[[97, 98], [99, 100]]
6. Bad size raises
memoryview(b'abc').cast('H')
Returns
TypeError: memoryview: length is not a multiple of itemsize

Pitfalls

1. Native byte order, with no way to override
cast reads multi-byte values in the machine's own order. The same bytes give different integers on a little-endian and a big-endian CPU, so results are not portable across architectures.
Platform dependent
memoryview(b'abcd').cast('H').tolist()
[25185, 25699] here; different on big-endian
Be explicit
import struct
struct.unpack('>2H', b'abcd')
(24930, 25444) everywhere
2. The byte length must divide evenly
Casting three bytes to 16-bit elements cannot work, and it raises rather than truncating. Slice to a multiple of the item size first.
Not a multiple
memoryview(b'abc').cast('H')
TypeError: memoryview: length is not a multiple of itemsize
Trim first
memoryview(b'abc')[:2].cast('H')
one element
3. len() changes meaning
After casting, len is the number of ELEMENTS, not bytes. Code that assumed a byte count silently reads the wrong amount — use nbytes when you mean bytes.
Elements, not bytes
len(memoryview(b'abcd').cast('H'))
2
Ask for bytes
memoryview(b'abcd').cast('H').nbytes
4
4. It only works on contiguous views
A sliced view with a step is not contiguous, so casting it raises. This is the usual reason a cast that works on fresh data fails on a slice.
Strided view
memoryview(b'abcdefgh')[::2].cast('H')
TypeError: memoryview: casts are restricted to C-contiguous views
Copy first
memoryview(bytes(memoryview(b'abcdefgh')[::2])).cast('H')
contiguous, so castable

When to use

Use it
  • Reading a binary buffer as wider numbers without copying
  • Working with data from array, mmap or a C extension
  • Reshaping a flat buffer into dimensions
  • Hot paths where struct.unpack would allocate too much
Reach for something else
  • Cross-platform binary formats → struct with an explicit endianness
  • Non-contiguous or strided views → copy first
  • Numeric work of any size → numpy handles this far better

Notes

Complexity
O(1) — no data is touched, only the view metadata changes
Return
A new memoryview sharing the original memory
CPython impl
Objects/memoryobject.c :: memory_cast
Memory
No copying; the new view keeps the underlying buffer alive
Thread-safe
The cast itself is safe; concurrent writes to the buffer are not

FAQ

No. The bytes are untouched — only the rule for grouping them into elements changes. Casting to a wider type and back always returns the original bytes exactly.

view.cast('H').cast('B').tobytes() == view.tobytes()
# True

History

3.3
memoryview.cast added alongside broader multi-dimensional buffer support.