Python memoryview 函数
上次修改时间:2025 年 4 月 11 日
本综合指南探讨了 Python 的 memoryview
函数,它提供了一种内存高效的方式来访问对象的缓冲区协议。我们将介绍二进制数据处理、内存效率和实际示例。
基本定义
memoryview
函数返回一个 memory view 对象,该对象公开对象的缓冲区协议,而无需复制其内存。它允许直接访问对象的内存。
主要特点:适用于类字节对象(bytes、bytearray、array.array),支持切片和索引,并支持零拷贝操作。它是大型二进制数据处理的理想选择。
Bytes 的基本用法
这是 bytes 的简单用法,展示了 memoryview
如何提供对底层数据的访问,而无需创建副本。
data = b'Python memoryview' mv = memoryview(data) # Access elements print(mv[0]) # 80 (ASCII 'P') print(mv[7]) # 109 (ASCII 'm') # Slicing print(mv[7:13].tobytes()) # b'memory'
此示例显示了 bytes 上的基本 memoryview
操作。我们可以将单个字节作为整数访问,或者创建切片而无需复制数据。
tobytes()
方法在需要时将切片转换回 bytes。Memory view 有效地维护原始数据的结构。
使用 Bytearray 修改数据
Memory view 可以修改像 bytearray 这样的可变对象。此示例演示了二进制数据的就地修改。
data = bytearray(b'Python is great!') mv = memoryview(data) # Modify through memoryview mv[7:9] = b'was' print(data) # bytearray(b'Python was great!') # Change single byte mv[0] = 112 # lowercase 'p' print(data) # bytearray(b'python was great!')
该示例展示了 memoryview
如何直接修改底层 bytearray。通过 view 进行的更改会影响原始数据。
这对于复制成本很高的大型数据集尤其有用。Memory view 提供了进入原始数据结构的窗口。
使用数组
Memory view 可以高效地与 array.array 对象一起使用。此示例演示了无需复制数据的数值数组处理。
import array numbers = array.array('i', [10, 20, 30, 40, 50]) mv = memoryview(numbers) # Access elements print(mv[2]) # 30 # Modify through view mv[1:4] = array.array('i', [25, 35, 45]) print(numbers) # array('i', [10, 25, 35, 45, 50])
该示例展示了 memoryview
如何有效地处理数值数组。该 view 维护数组的类型(此处“i”表示有符号整数)。
这种方法对于大型数值数据集来说是内存高效的,避免了在处理过程中创建中间副本的开销。
图像处理示例
这个实际示例演示了如何使用 memoryview
进行高效的图像像素操作,而无需复制整个图像数据。
def invert_colors(image_data): mv = memoryview(image_data) for i in range(len(mv)): mv[i] = 255 - mv[i] return mv # Simulate image data (RGBA pixels) pixels = bytearray([100, 150, 200, 255, 50, 75, 100, 255]) inverted = invert_colors(pixels) print(list(inverted)) # [155, 105, 55, 0, 205, 180, 155, 0]
该示例展示了一个简单的图像处理操作(颜色反转),使用了 memoryview
。该操作在像素数据上就地执行。
对于真实图像,这种方法避免了在处理过程中创建大型图像缓冲区的修改副本的内存开销。
内存效率比较
此示例比较了直接切片和 memoryview 切片之间的内存使用情况,展示了内存效率优势。
import sys large_data = bytearray(10_000_000) # 10MB of zeros # Traditional slicing (creates copy) slice_copy = large_data[1_000_000:9_000_000] print(f"Slice copy size: {sys.getsizeof(slice_copy)/1_000_000:.2f} MB") # Memoryview slicing (no copy) mv = memoryview(large_data) mv_slice = mv[1_000_000:9_000_000] print(f"Memoryview slice size: {sys.getsizeof(mv_slice)/1_000_000:.2f} MB")
该示例清楚地展示了 memoryview
的内存优势。传统的切片创建了一个 8MB 的副本,而 memoryview 切片非常小。
这证明了为什么 memoryview
对于内存效率至关重要的大型数据处理至关重要。
最佳实践
- 用于大型数据: 非常适合高效处理大型二进制数据集
- 防止内存泄漏: 使用完 memory view 后使用
mv.release()
释放它们 - 类型感知: 注意底层数据类型格式
- 可变与不可变: 仅修改可变对象(bytearray、数组)
- 上下文管理器: 使用
with
块进行自动资源管理
资料来源
作者
列出所有 Python 教程。