上一篇文章:Python 标准库 —13、内置类型:二进制序列类型 (bytes, bytearray)
下一篇文章:
内存视图
memoryview 对象允许 Python 代码访问一个对象的内部数据,只要该对象支持 缓冲区协议 而无需进行拷贝。
class memoryview(obj)
创建一个引用 obj 的 memoryview。obj 必须支持缓冲区协议。支持缓冲区协议的内置对象包括 bytes 和 bytearray。memoryview 具有 元素 的概念,即由原始对象 obj 所处理的基本内存单元。对于许多简单类型例如 bytes 和 bytearray 来说,一个元素就是一个字节,但是其他的类型例如 array.array 可能有更大的元素。len(view) 与 tolist 的长度相等。如果 view.ndim = 0,则其长度为 1。如果 view.ndim = 1,则其长度等于 view 中元素的数量。对于更高的维度,其长度等于表示 view 的嵌套列表的长度。itemsize 属性可向你给出单个元素所占的字节数。memoryview 支持通过切片和索引访问其元素。一维切片的结果将是一个子视图:
>>> v = memoryview(b'abcefg')
>>> v[1]
98
>>> v[-1]
103
>>> v[1:4]
<memory at 0x7f3ddc9f4350>
>>> bytes(v[1:4])
b'bce'
如果 format 是一个来自于 struct 模块的原生格式说明符,则也支持使用整数或由整数构成的元组进行索引,并返回具有正确类型的单个 元素。一维内存视图可以使用一个整数或由一个整数构成的元组进行索引。多维内存视图可以使用由恰好 ndim 个整数构成的元素进行索引,ndim 即其维度。零维内存视图可以使用空元组进行索引。这里是一个使用非字节格式的例子:
>>> import array
>>> a = array.array('l', [-11111111, 22222222, -33333333, 44444444])
>>> m = memoryview(a)
>>> m[0]
-11111111
>>> m[-1]
44444444
>>> m[::2].tolist()
[-11111111, -33333333]
如果下层对象是可写的,则内存视图支持一维切片赋值。改变大小则不被允许:
>>> data = bytearray(b'abcefg')
>>> v = memoryview(data)
>>> v.readonly
False
>>> v[0] = ord(b'z')
>>> data
bytearray(b'zbcefg')
>>> v[1:4] = b'123'
>>> data
bytearray(b'z123fg')
>>> v[2:3] = b'spam'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: memoryview assignment: lvalue and rvalue have different structures
>>> v[2:6] = b'spam'
>>> data
bytearray(b'z1spam')
由带有格式符号 'B', 'b' 或 'c' 的可哈希(只读)类型构成的一维内存视图同样是可哈希的。哈希定义为 hash(m) == hash(m.tobytes()):
>>> v = memoryview(b'abcefg')
>>> hash(v) == hash(b'abcefg')
True
>>> hash(v[2:4]) == hash(b'ce')
True
>>> hash(v[::-2]) == hash(b'abcefg'[::-2])
True
在 3.3 版更改: 一维内存视图现在可以被切片。带有格式符号 'B', 'b' 或 'c' 的一维内存视图现在是可哈希的。在 3.4 版更改: 内存视图现在会自动注册为 collections.abc.Sequence
在 3.5 版更改: 内存视图现在可使用整数元组进行索引。memoryview 具有以下一些方法:
__eq__(exporter)
memoryview 与 PEP 3118 中的导出器这两者如果形状相同,并且如果当使用 struct 语法解读操作数的相应格式代码时所有对应值都相同,则它们就是等价的。对于 tolist() 当前所支持的 struct 格式字符串子集,如果 v.tolist() == w.tolist() 则 v 和 w 相等:
>>> import array
>>> a = array.array('I', [1, 2, 3, 4, 5])
>>> b = array.array('d', [1.0, 2.0, 3.0, 4.0, 5.0])
>>> c = array.array('b', [5, 3, 1])
>>> x = memoryview(a)
>>> y = memoryview(b)
>>> x == a == y == b
True
>>> x.tolist() == a.tolist() == y.tolist() == b.tolist()
True
>>> z = y[::-2]
>>> z == c
True
>>> z.tolist() == c.tolist()
True
如果两边的格式字符串都不被 struct 模块所支持,则两对象比较结果总是不相等(即使格式字符串和缓冲区内容相同):
>>> from ctypes import BigEndianStructure, c_long
>>> class BEPoint(BigEndianStructure):
... _fields_ = [("x", c_long), ("y", c_long)]
...
>>> point = BEPoint(100, 200)
>>> a = memoryview(point)
>>> b = memoryview(point)
>>> a == point
False
>>> a == b
False
请注意,与浮点数的情况一样,对于内存视图对象来说,v is w 也 并不 意味着 v == w。在 3.3 版更改: 之前的版本比较原始内存时会忽略条目的格式与逻辑数组结构。
tobytes()
将缓冲区中的数据作为字节串返回。这相当于在内存视图上调用 bytes 构造器。
>>> m = memoryview(b"abc")
>>> m.tobytes()
b'abc'
>>> bytes(m)
b'abc'
对于非连续数组,结果等于平面化表示的列表,其中所有元素都转换为字节串。tobytes() 支持所有格式字符串,不符合 struct 模块语法的那些也包括在内。
hex()
返回一个字符串对象,其中分别以两个十六进制数码表示缓冲区里的每个字节。
>>> m = memoryview(b"abc")
>>> m.hex()
'616263'
3.5 新版功能.
tolist()
将缓冲区内的数据以一个元素列表的形式返回。
>>> memoryview(b'abc').tolist()
[97, 98, 99]
>>> import array
>>> a = array.array('d', [1.1, 2.2, 3.3])
>>> m = memoryview(a)
>>> m.tolist()
[1.1, 2.2, 3.3]
在 3.3 版更改: tolist() 现在支持 struct 模块语法中的所有单字符原生格式以及多维表示形式。
release()
释放由内存视图对象所公开的底层缓冲区。许多对象在被视图所获取时都会采取特殊动作(例如,bytearray 将会暂时禁止调整大小);因此,调用 release() 可以方便地尽早去除这些限制(并释放任何多余的资源)。在此方法被调用后,任何对视图的进一步操作将引发 ValueError (release() 本身除外,它可以被多次调用 ):
>>> m = memoryview(b'abc')
>>> m.release()
>>> m[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: operation forbidden on released memoryview object
使用 with 语句,可以通过上下文管理协议达到类似的效果:
>>>
>>> with memoryview(b'abc') as m:
... m[0]
...
97
>>> m[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: operation forbidden on released memoryview object
3.2 新版功能.
cast(format[, shape])
将内存视图转化为新的格式或形状。shape 默认为 [byte_length//new_itemsize],这意味着结果视图将是一维的。返回值是一个新的内存视图,但缓冲区本身不会被复制。支持的转化有 1D -> C-contiguous 和 C-contiguous -> 1D。目标格式仅限于 struct 语法中的单一元素原生格式。其中一种格式必须为字节格式 ('B', 'b' 或 'c')。结果的字节长度必须与原始长度相同。将 1D/long 转换为 1D/unsigned bytes:
>>> import array
>>> a = array.array('l', [1,2,3])
>>> x = memoryview(a)
>>> x.format
'l'
>>> x.itemsize
8
>>> len(x)
3
>>> x.nbytes
24
>>> y = x.cast('B')
>>> y.format
'B'
>>> y.itemsize
1
>>> len(y)
24
>>> y.nbytes
24
将 1D/unsigned bytes 转换为 1D/char:
>>> b = bytearray(b'zyz')
>>> x = memoryview(b)
>>> x[0] = b'a'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: memoryview: invalid value for format "B"
>>> y = x.cast('c')
>>> y[0] = b'a'
>>> b
bytearray(b'ayz')
将 1D/bytes 转换为 3D/ints 再转换为 1D/signed char:
>>>
>>> import struct
>>> buf = struct.pack("i"*12, *list(range(12)))
>>> x = memoryview(buf)
>>> y = x.cast('i', shape=[2,2,3])
>>> y.tolist()
[[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]]]
>>> y.format
'i'
>>> y.itemsize
4
>>> len(y)
2
>>> y.nbytes
48
>>> z = y.cast('b')
>>> z.format
'b'
>>> z.itemsize
1
>>> len(z)
48
>>> z.nbytes
48
将 1D/unsigned char 转换为 2D/unsigned long:
>>> buf = struct.pack("L"*6, *list(range(6)))
>>> x = memoryview(buf)
>>> y = x.cast('L', shape=[2,3])
>>> len(y)
2
>>> y.nbytes
48
>>> y.tolist()
[[0, 1, 2], [3, 4, 5]]
3.3 新版功能.
在 3.5 版更改: 当转换为字节视图时,源格式将不再受限。还存在一些可用的只读属性:### obj
内存视图的下层对象:
>>>
>>> b = bytearray(b'xyz')
>>> m = memoryview(b)
>>> m.obj is b
True
3.3 新版功能.
### nbytes
nbytes == product(shape) * itemsize == len(m.tobytes())。这是数组在连续表示时将会占用的空间总字节数。它不一定等于 len(m):
>>> import array
>>> a = array.array('i', [1,2,3,4,5])
>>> m = memoryview(a)
>>> len(m)
5
>>> m.nbytes
20
>>> y = m[::2]
>>> len(y)
3
>>> y.nbytes
12
>>> len(y.tobytes())
12
多维数组:
>>> import struct
>>> buf = struct.pack("d"*12, *[1.5*x for x in range(12)])
>>> x = memoryview(buf)
>>> y = x.cast('d', shape=[3,4])
>>> y.tolist()
[[0.0, 1.5, 3.0, 4.5], [6.0, 7.5, 9.0, 10.5], [12.0, 13.5, 15.0, 16.5]]
>>> len(y)
3
>>> y.nbytes
96
3.3 新版功能.
### readonly
一个表明内存是否只读的布尔值。### format
一个字符串,包含视图中每个元素的格式(表示为 struct 模块样式)。内存视图可以从具有任意格式字符串的导出器创建,但某些方法 (例如 tolist()) 仅限于原生的单元素格式。在 3.3 版更改: 格式 'B' 现在会按照 struct 模块语法来处理。这意味着 memoryview(b'abc')[0] == b'abc'[0] == 97。### itemsize
memoryview 中每个元素以字节表示的大小:
>>> import array, struct
>>> m = memoryview(array.array('H', [32000, 32001, 32002]))
>>> m.itemsize
2
>>> m[0]
32000
>>> struct.calcsize('H') == m.itemsize
True
### ndim
一个整数,表示内存所代表的多维数组具有多少个维度。### shape
一个整数元组,通过 ndim 的长度值给出内存所代表的 N 维数组的形状。在 3.3 版更改: 当 ndim = 0 时值为空元组而不再为 None。### strides
一个整数元组,通过 ndim 的长度给出以字节表示的大小,以便访问数组中每个维度上的每个元素。在 3.3 版更改: 当 ndim = 0 时值为空元组而不再为 None。### suboffsets
供 PIL 风格的数组内部使用。该值仅作为参考信息。### c_contiguous
一个表明内存是否为 C-contiguous 的布尔值。3.3 新版功能.
### f_contiguous
一个表明内存是否为 Fortran contiguous 的布尔值。3.3 新版功能.
### contiguous
一个表明内存是否为 contiguous 的布尔值。3.3 新版功能.
> 上一篇文章:[Python 标准库 ---13、内置类型:二进制序列类型 ( bytes, bytearray)][1]
> 下一篇文章: