Python-- memryview 介绍

Python 中的 memoryview

memoryview 是 Python 提供的一个内建类,允许你在不复制数据的情况下操作字节数据。它提供了一种有效的方式来访问和操作可变数据类型(如字节对象、字节数组、bytearray 等)的内存数据。

memoryview 对象能够访问数据的内部内存,不需要复制数据,从而提供更高效的内存使用和操作。它对于处理大数据、图像、音频、二进制文件等非常有用。



1. memoryview 基本概念

  • 内存视图(memory view) 是一种可以在原始数据(如 bytearraybytes 对象)上创建引用,而不需要复制数据的方法。
  • 它允许你按需切片、读取和修改字节数据。
  • 支持多维数组(例如,NumPy 数组)视图,类似于数组切片操作。


2. 创建和使用 memoryview

可以通过 memoryview() 函数创建一个内存视图对象,传入的数据对象必须支持缓冲区协议(例如 bytesbytearray)。

基本示例:

# 创建一个 bytes 对象
data = bytearray(b"hello world")

# 创建一个 memoryview 对象
mv = memoryview(data)

# 访问第一个元素
print(mv[0])  # 输出: 104 (对应 'h' 的 ASCII 值)

# 修改 memoryview 中的元素
mv[0] = 72  # 'H'
print(data)  # 输出: bytearray(b'Hello world')
  • memoryview 创建后,可以直接像访问列表一样访问数据,但它并不会复制数据。


3. 内存视图的切片

内存视图支持切片,允许你操作和访问数据的子集。这样可以有效避免不必要的内存拷贝。

data = bytearray(b"hello world")
mv = memoryview(data)

# 切片操作
slice_view = mv[0:5]  # 访问前5个字节
print(slice_view.tobytes())  # 输出: b'hello'

# 切片修改
slice_view[0] = 72  # 'H'
print(data)  # 输出: bytearray(b'Hello world')
  • 注意:tobytes() 方法可以将 memoryview 转换回字节对象。


4. 支持多维数据(如 NumPy 数组)

memoryview 不仅仅可以应用于一维的 bytesbytearray,它也可以用来处理多维数据(例如通过 numpy 创建的数组)。

示例:

import numpy as np

# 创建一个二维 numpy 数组
arr = np.array([[1, 2, 3], [4, 5, 6]])

# 创建 memoryview
mv = memoryview(arr)

# 访问和修改内存视图
print(mv[0, 0])  # 输出: 1
mv[0, 0] = 10
print(arr)  # 输出: [[10  2  3] [ 4  5  6]]
  • 对于多维数组,memoryview 使用逗号(,)进行索引和切片。


5. 读取和写入 memoryview

memoryview 使你能够在不创建副本的情况下,读取和修改原始数据。你可以用它来高效地处理和转换数据。

# 创建一个 bytearray
data = bytearray(b"hello")

# 创建 memoryview
mv = memoryview(data)

# 读取数据
print(mv[1])  # 输出: 101 (对应 'e')

# 修改数据
mv[1] = 105  # 'i'
print(data)  # 输出: bytearray(b'hi')
  • memoryview 不会复制数据,它直接修改原始数据。


6. memoryview 的方法和属性

memoryview 提供了一些有用的方法和属性来访问和操作数据:

  • tobytes():返回内存视图的字节对象副本。
  • tolist():返回内存视图的列表副本(适用于多维数据)。
  • format:返回数据的格式字符串。
  • ndim:返回视图的维度数。
  • shape:返回数据的形状(适用于多维数据)。
  • itemsize:返回每个元素的大小(以字节为单位)。
  • readonly:检查视图是否是只读的。

示例:

data = bytearray(b"hello world")

# 创建 memoryview
mv = memoryview(data)

# 获取数据的字节副本
bytes_copy = mv.tobytes()
print(bytes_copy)  # 输出: b'hello world'

# 获取数据的元素大小
print(mv.itemsize)  # 输出: 1,因为每个字节的大小是1

# 检查是否只读
print(mv.readonly)  # 输出: False

# 获取数据的格式
print(mv.format)  # 输出: 'B' 表示无符号字节


7. memoryview 和 bytearray

bytearray 是一个支持缓冲区协议的对象,因此可以直接与 memoryview 交互。通常,memoryview 用于高效地操作 bytearraybytes 或类似对象。

示例:

data = bytearray(b"hello world")

# 创建 memoryview
mv = memoryview(data)

# 访问并修改数据
print(mv[0])  # 输出: 104 ('h' 的 ASCII 值)
mv[0] = 72  # 'H'

print(data)  # 输出: bytearray(b'Hello world')


8. memoryview 的优点

  • 性能memoryview 允许对大数据对象(如大型字节数组、图片、音频数据等)进行切片和修改时不进行复制,节省内存。
  • 内存共享:多个 memoryview 对象可以共享同一块内存区域,因此更适合大规模数据操作。
  • 灵活性:能够访问和修改多维数组的数据,特别适合与 NumPy 数组配合使用。


总结

memoryview 提供了一个高效的方式来操作字节数据,避免了不必要的数据复制,尤其在处理大量数据时,能够显著提高性能。通过 memoryview,你可以在不创建副本的情况下切片、读取和修改数据,从而有效节省内存,尤其适用于处理大文件、图像或数组等场景。



memoryview.cast() 是 Python 中 memoryview 对象的一个方法,允许你对内存视图的内容进行类型转换。通过 cast() 方法,你可以重新解释原始数据的结构,使其以不同的数据类型或格式进行访问,而不需要复制数据。

memoryview.cast() 的基本用途

cast() 方法用于将内存视图的元素类型改变为其他类型,这对于处理数据的二进制表示特别有用。通过 cast(),你可以将一个字节序列或数组解释为另一种数据类型(例如将字节数据解释为 intfloat 类型的数组),而不需要实际拷贝内存数据。

语法

memoryview.cast(format)
  • format:表示目标数据类型的字符串。它是一个格式字符,遵循 Python 的 struct 模块的格式字符串规则,通常是用于表示 C 语言中的数据类型,如 'B'(无符号字节)、'H'(无符号短整型)、'I'(无符号整型)、'f'(浮点数)等。

返回值

  • 返回一个新的 memoryview 对象,该对象以新的数据类型(由 format 指定)来解释原始数据。

常见的 format 字符

  • 'B':无符号字节(0–255
  • 'H':无符号短整型(0–65535
  • 'I':无符号整型(0–4294967295
  • 'f':32 位浮点数
  • 'd':64 位浮点数


示例:使用 cast() 转换数据类型

示例 1:将字节数据转换为整数数组

# 原始字节数据
data = bytearray(b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00')

# 创建 memoryview
mv = memoryview(data)

# 使用 cast() 将字节数据解释为无符号整数(4 字节)
mv_int = mv.cast('I')  # 4 字节无符号整数('I')

print(list(mv_int))  # 输出: [1, 2, 3]
  • 在这个例子中,原始数据是 bytearray,它包含了四个字节的数据。我们通过 cast('I') 将这些字节解释为无符号的 4 字节整数数组,结果是 [1, 2, 3]

示例 2:将字节数据转换为浮点数数组

# 原始字节数据(4字节每个元素)
data = bytearray(b'\x00\x00\x80\x3f\x00\x00\x00\x40')

# 创建 memoryview
mv = memoryview(data)

# 使用 cast() 将字节数据解释为浮点数(4字节)
mv_float = mv.cast('f')  # 4 字节浮点数('f')

print(list(mv_float))  # 输出: [1.0, 2.0]
  • 这里,我们将字节数据转换为浮点数,每 4 个字节解释为一个浮点数。b'\x00\x00\x80\x3f' 对应于浮点数 1.0b'\x00\x00\x00\x40' 对应于 2.0


cast() 的优势

  • 内存共享:cast() 方法不会复制数据,它返回的 memoryview 只是对原始数据的一个新视图,重新解释数据的格式。这样,你可以在不创建副本的情况下查看数据的不同类型表示。
  • 高效:对于大型数据集,cast() 可以避免数据的复制,并且允许以不同的方式访问和修改内存中的内容。
  • 适用场景:cast() 对于需要高效处理二进制数据的场景特别有用,比如图像处理、文件解析、网络数据处理等。


使用场景

  • 处理二进制协议:在处理二进制数据协议时,你可能需要将字节数据按不同的类型进行解析,cast() 可以高效地实现这一点。
  • 与 NumPy 配合使用:memoryview 可以与 NumPy 数组结合使用,cast() 可以将字节流解释为 NumPy 数组中的其他数据类型。例如,你可以将原始字节数据视为整数数组、浮点数组等。
  • 数据转换:cast() 在需要将字节数据视为不同数据类型(如将字节数据解释为整数、浮点数等)时非常有用。


总结

  • cast()memoryview 对象的方法,用于将内存视图的数据类型进行转换。它非常高效,因为它不需要复制数据,只是通过不同的方式解释内存中的数据。
  • 常见用途:它在处理二进制数据、文件操作、图像处理和科学计算等场景中非常有用,特别是在需要高效处理大数据时。
文章标签:

评论(0)