ZetCode

Python memoryview 函数

上次修改时间:2025 年 4 月 11 日

本综合指南探讨了 Python 的 memoryview 函数,它提供了一种内存高效的方式来访问对象的缓冲区协议。我们将介绍二进制数据处理、内存效率和实际示例。

基本定义

memoryview 函数返回一个 memory view 对象,该对象公开对象的缓冲区协议,而无需复制其内存。它允许直接访问对象的内存。

主要特点:适用于类字节对象(bytes、bytearray、array.array),支持切片和索引,并支持零拷贝操作。它是大型二进制数据处理的理想选择。

Bytes 的基本用法

这是 bytes 的简单用法,展示了 memoryview 如何提供对底层数据的访问,而无需创建副本。

basic_memoryview.py
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 这样的可变对象。此示例演示了二进制数据的就地修改。

modify_data.py
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 对象一起使用。此示例演示了无需复制数据的数值数组处理。

array_processing.py
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 进行高效的图像像素操作,而无需复制整个图像数据。

image_processing.py
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 切片之间的内存使用情况,展示了内存效率优势。

memory_efficiency.py
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 对于内存效率至关重要的大型数据处理至关重要。

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程