用 memoryview 替代切片可避免底层字节拷贝,但仅对 bytes、bytearray、array.array、NumPy 数组等支持缓冲协议的对象有效;对 list 或 str 无效,因其不满足缓冲协议要求。

直接说结论:用 memoryview 替代切片可避免底层字节拷贝,但仅对支持缓冲协议的对象(如 bytes、bytearray、array.array、NumPy 数组)有效;对 list 或 str 无效。
为什么切片会拷贝数据?
Python 中普通切片(如 b[10:20])默认创建新对象。对 bytes 来说,这意味分配新内存并复制对应字节——尤其处理大块二进制数据(如网络包、文件片段)时,性能和内存开销明显。
而 memoryview 是一个“零拷贝视图”,它不拥有数据,只记录起始地址、长度和步长,类似 C 的指针偏移。
常见错误现象:memoryview(b'hello')[1:4] 看似切片,实际返回的仍是 memoryview 对象,不是 bytes;若误当成 bytes 使用(比如传给需要 bytes 的函数),会报 TypeError: expected bytes, bytearray or buffer object。
立即学习“Python免费学习笔记(深入)”;
怎么正确创建和使用 memoryview 切片?
关键点:先确保源对象支持缓冲协议,再用 memoryview 包裹,最后用切片语法获取子视图(仍为 memoryview)。
-
mv = memoryview(b'abcdefgh')→ 创建视图 -
sub = mv[2:6]→ 不拷贝,sub指向原bytes的第 2~5 字节 - 需要
bytes时才显式转换:bytes(sub)(此时才发生拷贝) - 可直接参与字节级操作:
sub[0] == 99(c的 ASCII 值),sub.tolist()等
注意:memoryview 切片不可变(若源是 bytes);若需修改,源必须是可写的(如 bytearray):
ba = bytearray(b'hello') mv = memoryview(ba) mv[0] = 72 # OK,ba 变成 b'Hello'
哪些类型能用?哪些不能?
支持缓冲协议的类型才能构造 memoryview,否则抛 TypeError: memoryview: a bytes-like object is required。
- ✅ 支持:
bytes、bytearray、array.array('B')、NumPyndarray、ctypes数组 - ❌ 不支持:
str(Unicode 字符串,非字节序列)、list、tuple、dict - ⚠️ 注意:
array.array('i')(整数数组)也支持,但切片后访问元素是int类型,不是字节;memoryview的行为取决于底层元素大小和格式
兼容性影响:Python 2.7+ 均支持 memoryview,但某些旧版 NumPy 或自定义类可能未完整实现缓冲协议接口(__buffer__),需实测。
容易被忽略的生命周期陷阱
memoryview 引用的是原始对象的内存,如果原始对象被释放或重新分配(如 bytearray 扩容、del 掉源变量),视图可能失效或引发 ValueError: memoryview has been detached。
典型场景:
- 函数返回
memoryview,但内部源对象是局部bytearray→ 出作用域后视图悬空 - 对
bytearray进行追加(.extend())导致底层 realloc → 原memoryview自动 detach
安全做法:只在明确控制源对象生命周期的上下文中使用;避免跨函数传递裸 memoryview;必要时用 .tobytes() 或 .copy() 转为独立副本。


















