memoryview.tolist()

Mostly a debugging tool. Seeing [104, 105] instead of b'hi' is what makes byte values readable when you are checking a protocol by hand.

Memoryview methodPython 2.7+Live demo
Common call
view.tolist()
Returns
list of ints for a byte view
Replaces
list(view), which gives the same result
Watch out
far larger than the buffer — each int is a full Python object
memoryview.tolist()
→ list

Demo

Live evaluation
Try:
Inputs
sstrtext to view as bytes
Output
memoryview(bytes('abc', 'utf-8')).tolist()
[97, 98, 99]

Each byte becomes an int from 0 to 255. "abc" gives [97, 98, 99] — the ASCII codes. The non-ascii case shows why this is a BYTE list and not a character list: the accented letter is encoded as two UTF-8 bytes, so a five-character string produces six numbers. The digits case is a common trip-up: "123" gives [49, 50, 51], the character codes, not the values one, two and three.

Common patterns

Inspect a binary protocol by hand
Byte values are far easier to check against a spec than an escaped bytes repr.
print(memoryview(packet)[:8].tolist())
Compare buffers element by element
A list diff points at the exact offset that differs.
a, b = memoryview(x).tolist(), memoryview(y).tolist()
first_diff = next(i for i, (p, q) in enumerate(zip(a, b)) if p != q)
Assert on byte values in a test
Reads better in a failure message than a bytes literal.
assert memoryview(out).tolist() == [0, 1, 255]

Examples

1. ASCII codes
memoryview(b'abc').tolist()
Returns
[97, 98, 99]
2. Two letters
memoryview(b'hi').tolist()
Returns
[104, 105]
3. Digits are codes
memoryview(b'123').tolist()
Returns
[49, 50, 51]
4. Empty
memoryview(b'').tolist()
Returns
[]
5. Same as list()
list(memoryview(b'abc'))
Returns
[97, 98, 99]
6. Non-ascii is multi-byte
memoryview('é'.encode()).tolist()
Returns
[195, 169]

Pitfalls

1. Digits give character codes, not values
b'123' is the characters one, two and three, whose ASCII codes are 49, 50 and 51. Reading the list as the number one hundred and twenty-three is a classic parsing bug.
Not the digits
memoryview(b'123').tolist()
[49, 50, 51]
Decode and parse
int(memoryview(b'123').tobytes())
123
2. One entry per BYTE, not per character
The view knows nothing about text encodings. A non-ASCII character occupies several bytes and therefore several list entries, so the length does not match the string length.
Six for five chars
len(memoryview('héllo'.encode()).tolist())
6
Count characters
len('héllo')
5
3. It is far bigger than the buffer
Every byte becomes a full Python int object. A one-megabyte buffer becomes a list costing tens of megabytes, which defeats the memory saving a view was chosen for.
Huge allocation
memoryview(one_mb_buffer).tolist()
tens of MB of int objects
Index what you need
view[0], view[1]
two ints

When to use

Use it
  • Debugging binary formats where byte values matter
  • Test assertions that should read as numbers
  • Comparing two buffers to find the first differing offset
Reach for something else
  • Large buffers — the list dwarfs the data
  • You want the raw bytes → tobytes
  • You want a compact hex view → hex

Notes

Complexity
O(n) — one Python object created per element
Return
A new list; for a byte view, ints in the range 0 to 255
CPython impl
Objects/memoryobject.c :: memory_tolist
Memory
Substantially larger than the buffer — a Python int per element
Thread-safe
A concurrently mutated source gives an inconsistent snapshot

FAQ

Because those are the ASCII codes for the characters one, two and three. A memoryview exposes raw bytes and never interprets them as text or numbers — decoding is always something you ask for explicitly.

ord('1')
# 49

History

2.7
memoryview introduced with tolist, replacing the older buffer type.
3.3
Extended to handle multi-dimensional and non-byte formats properly.