前面一篇学习了bytes和bytearray,这一篇学习其他的两个类型array和memoryview,同时会对struct模块和 codecs进行学习
高效的数字数组
此模块定义了一种对象类型,可以紧凑地表示由基本值(字符、整数、浮点数)组成的数组。数组是序列类型,其行为与列表非常相似,不同之处在于其中存储的对象类型是受限的,在数组对象创建时用单个字符的 类型码 来指定。已定义的类型码如下:
类型码 |
C 类型 |
Python 类型 |
以字节为单位的最小大小 |
备注 |
---|---|---|---|---|
|
signed char |
int |
1 |
|
|
unsigned char |
int |
1 |
|
|
wchar_t |
Unicode 字符 |
2 |
(1) |
|
signed short |
int |
2 |
|
|
unsigned short |
int |
2 |
|
|
signed int |
int |
2 |
|
|
unsigned int |
int |
2 |
|
|
signed long |
int |
4 |
|
|
unsigned long |
int |
4 |
|
|
signed long long |
int |
8 |
|
|
unsigned long long |
int |
8 |
|
|
float |
float |
4 |
|
|
double |
float |
8 |
注释:
(1)在不同的平台上,它可能为 16 位或 32 位。
在 3.9 版更改: array('u') 现在使用 wchar_t 作为 C 类型而不是已不建议使用的 Py_UNICODE。这个改变不会影响其行为,因为 Py_UNICODE 自 Python 3.3 起就是 wchar_t 的别名。从 3.3 版起不建议使用,将在 4.0 版中移除。值的实际表示是由机器架构(严格说是由 C 实现)决定的。实际大小可以通过 array.itemsize 属性来访问。
array.typecodes中定义了所有的类型码
>>> import array
>>> array.typecodes
'bBuhHiIlLqQfd'
语法:
class array.array(typecode[, initializer])
一个由 typecode 限制类型的新数组,并通过可选的 initializer 进行初始化。initializer 必须为一个列表、bytes-like object 或在合适类型元素上迭代的可迭代对象。
如果是一个列表或字符串,该 initializer 会被传给新数组的 fromlist(),frombytes() 或 fromunicode() 方法(见下)以将初始项添加到数组中。其它将可迭代对象将被传给 extend() 方法。
数组对象支持普通的序列操作如索引、切片、拼接和重复等。当使用切片赋值时,所赋的值必须为具有相同类型码的数组对象;所有其他情况都将引发 TypeError。数组对象也实现了缓冲区接口,可以用于所有支持 字节类对象 的场合。
成员typecode
在创建数组时指定的类型码字符。
成员itemsize
在内部表示中,单个数组项的长度,单位为字节。
长度与字符类型密切相关,实际是typecode和系统类型决定了itemsize
import array
arr = array.array('i',[0,1,1,3]) #创建array数组
print(arr) #array('i', [0, 1, 1, 3])
print(arr.typecode) #i
print(arr.itemsize) #4
array.frombytes(s)
添加来自字节串的项,将字符节解读为机器值的数组(相当于使用 fromfile() 方法从文件中读取数据)。
3.2 新版功能: fromstring() 被重命名为含义更准确的 frombytes()。
这个方法要求比较苛刻,要求array和s的长度一致,并且s只能是字节类串
import array
arr = array.array('i',[0,1,2,3]) #创建array数组
print(arr) #array('i', [0, 1, 2, 3])
print(arr.itemsize) #4
b1 = b'12'
print(f"{len(b1)=}") #len(b1)=2
#arr.frombytes(b1) #ValueError itemsize<>len(b1)
b2 = b'1234'
print(f"{len(b2)=}") #len(b2)=4
arr.frombytes(b2)
print(arr) #array('i', [0, 1, 2, 3, 875770417])
b3 = bytes([1,2,3,4])
print(f"{len(b3)=}")
arr.frombytes(b3)
print(arr) #array('i', [0, 1, 2, 3, 875770417, 67305985])
array.fromfile(f, n)
从 file object f 中读取 n 项并将它们添加到数组末尾。 如果可用数据少于 n 项,则会引发 EOFError,但可用的项仍然会被插入数组。
array.fromlist(list)
添加来自 list 的项。 这等价于 for x in list: a.append(x),区别在于如果发生类型错误,数组将不会被改变。
arr = array.array('i',[0,1,2,3]) #创建array数组
b4 = list([10,11])
arr.fromlist(b4)
print(arr) #array('i', [0, 1, 2, 3, 10, 11])
b5 = list(['ab', 'cd'])
#arr.fromlist(b5) #TypeError
array.fromunicode(s)
使用来自给定 Unicode 字符串的数组扩展数组。 数组必须是类型为 'u' 的数组;否则将引发 ValueError。 请使用 array.frombytes(unicodestring.encode(enc)) 来将 Unicode 数据添加到其他类型的数组。
array.append(x)
添加一个值为 x 的新项到数组末尾。
array.extend(iterable)
将来自 iterable 的项添加到数组末尾。 如果 iterable 是另一个数组,它必须具有 完全 相同的类型码;否则将引发 TypeError。 如果 iterable 不是一个数组,则它必须为可迭代对象并且其元素必须为可添加到数组的适当类型。
array.tobytes()
将数组转换为一个机器值数组并返回其字节表示(即相当与通过 tofile() 方法写入到文件的字节序列。)
3.2 新版功能: tostring() 被重命名为含义更准确的 tobytes()。
array.tofile(f)
将所有项(作为机器值)写入到 file object f。
array.tolist()
将数组转换为包含相同项的普通列表。
array.tounicode()
将数组转换为一个 Unicode 字符串。 数组必须是类型为 'u' 的数组;否则将引发 ValueError。 请使用 array.tobytes().decode(enc) 来从其他类型的数组生成 Unicode 字符串。
当一个数组对象被打印或转换为字符串时,它会表示为 array(typecode, initializer)。 如果数组为空则 initializer 会被省略,否则如果 typecode 为 'u' 则它是一个字符串,否则它是一个数字列表。 使用 eval() 保证能将字符串转换回具有相同类型和值的数组,只要 array 类已通过 from array import array 被引入。 例如:
>>> array.array('l')
array('l')
>>> array.array('u', 'hello \u2641')
array('u', 'hello ♁')
>>> array.array('l', [1,2,3,4,5,6])
array('l', [1, 2, 3, 4, 5, 6])
>>> array.array('d', [1.0,2.0,3.0,4.0,5.0,6.0])
array('d', [1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
array.insert(i, x)
将值 x 作为新项插入数组的 i 位置之前。 负值将被视为相对于数组末尾的位置。
import array
arr = array.array('i',[0,1,2,3]) #创建array数组
print(arr) #array('i', [0, 1, 2, 3])
print(arr.typecode) #i
print(arr.itemsize) #4
arr.append(100)
print(arr) #array('i', [0, 1, 1, 3, 100])
arr.insert(3,101)
print(arr) #array('i', [0, 1, 2, 101, 3, 100])
array.count(x)
返回 x 在数组中的出现次数。
array.index(x[, start[, stop]])
返回最小的 i 使得 i 为数组中首次出现的 x 的索引号。 指定可选参数 start 和 stop 以便在数组的一个子部分内部搜索 x。 如果未找到 x 则会引发 ValueError。
在 3.10 版更改: 添加了可选的 start 和 stop 形参。
sarray.pop([i])
从数组中移除序号为 i 的项并将其返回。 可选参数值默认为 -1,因此默认将移除并返回末尾项。
array.remove(x)
从数组中移除首次出现的 x。
array.reverse()
反转数组中各项的顺序。
array.buffer_info()
返回一个元组 (address, length) 给出存放数组内容的内存缓冲区的当前地址和长度(以元素个数为单位)。以字节为单位的的内存缓冲区大小可通过 array.buffer_info()[1] * array.itemsize 来计算。工作在需要内存地址的底层(因此天然地不够安全)的 I/O 接口上时,这有时会有用,例如某些 ioctl() 操作。只要数组还存在,并且没有对其应用过改变长度的操作,则返回的数值就是有效的。
备注 当在 C 或 C++ 编写的代码中使用数组对象时(这是有效使用此类信息的唯一方式),使用数组对象所支持的缓冲区接口更为适宜。 此方法仅保留用作向下兼容,应避免在新代码中使用。 缓冲区接口的文档参见 缓冲协议。
字节对调
array.byteswap()
“字节对调”所有数组项。 此方法只支持大小为 1, 2, 4 或 8 字节的值;对于其他值类型将引发 RuntimeError。 它适用于从不同字节序机器所生成的文件中读取数据的情况。
字节串数据的打包或解包.
格式串字符描述了打包和拆包时的数据格式,格式字符指定数据类型,特殊字符控制字节顺序、大小端和对齐方式。
格式字符串的第一个字符可用于指示打包数据的字节顺序,大小和对齐方式:
字符 |
字节顺序 |
大小 |
对齐方式 |
---|---|---|---|
|
按原字节 |
按原字节 |
按原字节 |
|
按原字节 |
标准 |
无 |
|
小端 |
标准 |
无 |
|
大端 |
标准 |
无 |
|
网络(=大端) |
标准 |
无 |
如果第一个字符不是其中之一,则假定为 '@'
。
本机大小和对齐方式是使用 C 编译器的 sizeof
表达式来确定的。 这总是会与本机字节顺序相绑定。
请注意 '@'
和 '='
之间的区别:两个都使用本机字节顺序,但后者的大小和对齐方式是标准化的。
形式 '!'
代表网络字节顺序总是使用在 IETF RFC 1700 中所定义的大端序。
没有什么方式能指定非本机字节顺序(强制字节对调);请正确选择使用 '<'
或 '>'
。
注释:
格式字符具有以下含义;C 和 Python 值之间的按其指定类型的转换应当是相当明显的。 ‘标准大小’列是指当使用标准大小时以字节表示的已打包值大小;也就是当格式字符串以 '<'
, '>'
, '!'
或 '='
之一开头的情况。 当使用本机大小时,已打包值的大小取决于具体的平台。
格式 |
C 类型 |
Python 类型 |
标准大小 |
备注 |
---|---|---|---|---|
|
填充字节 |
无 |
(7) |
|
|
char |
长度为 1 的字节串 |
1 |
|
|
signed char |
整数 |
1 |
(1), (2) |
|
unsigned char |
整数 |
1 |
(2) |
|
_Bool |
bool |
1 |
(1) |
|
short |
整数 |
2 |
(2) |
|
unsigned short |
整数 |
2 |
(2) |
|
int |
整数 |
4 |
(2) |
|
unsigned int |
整数 |
4 |
(2) |
|
long |
整数 |
4 |
(2) |
|
unsigned long |
整数 |
4 |
(2) |
|
long long |
整数 |
8 |
(2) |
|
unsigned long long |
整数 |
8 |
(2) |
|
|
整数 |
(3) |
|
|
|
整数 |
(3) |
|
|
(6) |
float |
2 |
(4) |
|
float |
float |
4 |
(4) |
|
double |
float |
8 |
(4) |
|
char[] |
字节串 |
(9) |
|
|
char[] |
字节串 |
(8) |
|
|
void* |
整数 |
(5) |
注释:
(1)“?”转换代码对应于C99定义的_Bool类型。如果此类型不可用,则使用char对其进行模拟。在标准模式中,它总是由一个字节表示。
(2)当尝试使用任何整数转换代码打包非整数时,如果非整数有__index__()方法,则在打包前调用该方法将参数转换为整数。
在 3.2 版更改: Added use of the __index__() method for non-integers.
(3)'n' 和 'N' 转换码仅对本机大小可用(选择为默认或使用 '@' 字节顺序字符)。 对于标准大小,你可以使用适合你的应用的任何其他整数格式。
(4)对于 'f', 'd' 和 'e' 转换码,打包表示形式将使用 IEEE 754 binary32, binary64 或 binary16 格式 (分别对应于 'f', 'd' 或 'e'),无论平台使用何种浮点格式。
(5)'P' 格式字符仅对本机字节顺序可用(选择为默认或使用 '@' 字节顺序字符)。 字节顺序字符 '=' 选择使用基于主机系统的小端或大端排序。 struct 模块不会将其解读为本机排序,因此 'P' 格式将不可用。
(6)IEEE 754 binary16 "半精度" 类型是在 IEEE 754 标准 的 2008 修订版中引入的。 它包含一个符号位,5 个指数位和 11 个精度位(明确存储 10 位),可以完全精确地表示大致范围在 6.1e-05 和 6.5e+04 之间的数字。 此类型并不被 C 编译器广泛支持:在一台典型的机器上,可以使用 unsigned short 进行存储,但不会被用于数学运算。
(7)当打包时,'x'将填充一个NULL字节.
(8)'p' 格式字符用于编码“Pascal 字符串”,即存储在由计数指定的 固定长度字节 中的可变长度短字符串。 所存储的第一个字节为字符串长度或 255 中的较小值。 之后是字符串对应的字节。 如果传入 pack() 的字符串过长(超过计数值减 1),则只有字符串前 count-1 个字节会被存储。 如果字符串短于 count-1,则会填充空字节以使得恰好使用了 count 个字节。 请注意对于 unpack(),'p' 格式字符会消耗 count 个字节,但返回的字符串永远不会包含超过 255 个字节。
(9)对于's'格式字符,计数被解释为字节的长度,而不是像其他格式字符那样的重复计数;例如,“10s”表示单个10字节字符串映射到单个Python字节字符串或从单个Python字节串映射,而“10c”表示10个单独的单字节字符元素(例如cccccccc)映射到10个不同的Python字节对象或从10个不同Python字节对象映射。如果未给定计数,则默认为1。对于打包,字符串会被适当地截断或填充空字节以使其适合。对于解包,生成的字节对象始终具有指定数量的字节。特殊情况下,“0s”表示单个空字符串(而“0c”表示0个字符)。
格式字符之前可以带有整数重复计数。 例如,格式字符串 '4h' 的含义与 'hhhh' 完全相同。
格式之间的空白字符会被忽略;但是计数及其格式字符中不可有空白字符。
当使用某一种整数格式 ('b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q') 打包值 x 时,如果 x 在该格式的有效范围之外则将引发 struct.error。
在 3.1 版更改: 在之前版本中,某些整数格式包装了超范围的值并会引发 DeprecationWarning 而不是 struct.error。
对于 '?' 格式字符,返回值为 True 或 False。 在打包时将会使用参数对象的逻辑值。 以本机或标准 bool 类型表示的 0 或 1 将被打包,任何非零值在解包时将为 True。
struct.Struct 是一个用于处理二进制数据的类,可以将二进制数据按照指定格式进行打包或解包。
语法:
class struct.Struct(format)
参数说明:
format:格式字符串。
返回一个struct对象(结构体,参考C)
import struct
values = (1, 'abcd'.encode('utf-8'), 2.7)
s = struct.Struct('I 4s f')
packed_data = s.pack(*values)
print(s)
print(s.format)
print('Original values:', values)
print('Format string :', s.format)
print('Uses :', s.size, 'bytes')
print('Packed Value :', packed_data.hex())
‘’'
<_struct.Struct object at 0x105791e90>
I 4s f
Original values: (1, b'abcd', 2.7)
Format string : I 4s f
Uses : 12 bytes
Packed Value : 0100000061626364cdcc2c40
‘''
语法:
struct.pack(format, v1, v2, ...)
参数说明:
返回一个 bytes 对象,其中包含根据格式字符串 format 打包的值 v1, v2, ... 参数个数必须与格式字符串所要求的值完全匹配。
该函数常用于将python的数据转换为C语言中所使用的二进制数据格式。
import struct
n = 1024
b = struct.pack('I', n)
print(b) # b'\x00\x04\x00\x00'
上述代码将一个无符号整数n转换为二进制字节串b,使用了'I'格式化字符。
import struct
s = 'hello'
b = struct.pack('5s', bytes(s, encoding='utf-8'))
print(b) # b'hello'
上述代码将字符串s转换为定长字节串b,使用了'5s'格式化字符。
import struct
f = 1.23
b = struct.pack('f', f)
print(b) # b'\xab\x1f\x9d?'
上述代码将单精度浮点数f转换为二进制字节串b,使用了'f'格式化字符。
import struct
# 定义一个结构体类型
student = struct.Struct('3s I 2s')
# 创建结构体对象
stu = student.pack(b'Bob', 20, b'McGraw')
# 解析结构体对象
name, age, school = student.unpack(stu)
print('name:', name.decode()) #name: Bob
print('age:', age) #age: 20
print('school:', school.decode()) #school: Mc
上述代码先定义了一个结构体类型,它包含了三个元素:长度为3的字符串、一个整数和长度为2的字符串。然后通过调用 Struct.pack() 函数将结构体对象stu打包,并且使用Struct.unpack()函数将其解包。
语法:
struct.unpack(format, buffer)
根据格式字符串 format 从缓冲区 buffer 解包(假定是由 pack(format, ...) 打包)。 结果为一个元组,即使其只包含一个条目。 缓冲区的字节大小必须匹配格式所要求的大小,如 calcsize() 所示。
import struct
# values = (1, 'abcd'.encode('utf-8'), 2.7)
# s = struct.Struct('I 4s f')
# packed_data = s.pack(*values)
# print(s)
# print(s.format)
#
# print('Original values:', values)
# print('Format string :', s.format)
# print('Uses :', s.size, 'bytes')
# print('Packed Value :', packed_data.hex())
hs='0100000061626364cdcc2c40'
bs=bytes.fromhex(hs)
s = struct.Struct('I 4s f')
values = s.unpack(bs)
print(values) #(1, b'abcd', 2.700000047683716)
import struct
s1 = b'He is not very happy!'
format = '2s 1x 2s 5x 4s 1x 6s'
b = struct.unpack(format, s1)
print(b) #(b'He', b'is', b'very', b'happy!')
s2 = struct.pack('2s 2s 4s 6s', *b)
print(s2) #b'Heisveryhappy!'
struct.pack_into(format, buffer, offset, v1, v2, ...)
根据格式字符串 format 打包 v1, v2, ... 等值并将打包的字节串写入可写缓冲区 buffer 从 offset 开始的位置。 请注意 offset 是必需的参数。
语法:
struct.unpack_from(format, /, buffer, offset=0)
对 buffer 从位置 offset 开始根据格式字符串 format 进行解包。 结果为一个元组,即使其中只包含一个条目。 缓冲区的字节大小从位置 offset 开始必须至少为 calcsize() 显示的格式所要求的大小。
import struct
import ctypes
values1 = (1314, b'I love you', 3.1415) # 查看格式化字符串可知,字符串必须为字节流类型。
s1 = struct.Struct('I10sf')
values2 = (b'No!Go away!', 444) # 查看格式化字符串可知,字符串必须为字节流类型。
s2 = struct.Struct('11sI')
buff = ctypes.create_string_buffer(s1.size + s2.size)
packed_data = s1.pack_into(buff, 0, *values1)
s2.pack_into(buff, s1.size, *values2)
s3 = struct.Struct('I10sf11sI')
unpacked_data = s3.unpack_from(buff, 0)
print('buff :', buff)
print('Packed Value :', buff.raw.hex())
print('Unpacked Type :', type(unpacked_data), ' Value:', unpacked_data)
‘’'
buff :
Packed Value : 2205000049206c6f766520796f750000560e49404e6f21476f20617761792100bc010000
Unpacked Type : Value: (1314, b'I love you', 3.1414999961853027, b'No!Go away!', 444)
‘''
根据格式串format从缓冲区buffer解包,结果为一个迭代器。
返回与格式字符串 format 相对应的结构的大小(亦即 pack(format, ...)
所产生的字节串对象的大小)。
memoryview 对象允许 Python 代码访问一个对象的内部数据。这个函数可以用于在 Python 中操作二进制数据,例如在处理音频、视频或图像文件时。使用memoryview()
函数可以提高处理效率,因为它允许您直接访问原始数据的内存,而无需创建临时副本。
class memoryview(object)
创建一个引用 object 的 memoryview 。 object 必须支持缓冲区协议。支持缓冲区协议的内置对象有 bytes 和 bytearray 。
memoryview 有 元素 的概念, 元素 指由原始 object 处理的原子内存单元。对于许多简单的类型,如 bytes 和 bytearray ,一个元素是一个字节,但其他类型,如 array.array 可能有更大的元素。
支持通过切片和索引访问其元素。 一维切片的结果将是一个子视图:
>>>v = memoryview(b'abcefg')
>>>v[1]
98
>>>v[-1]
103
>>>v[1:4]
>>>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 "", line 1, in
ValueError: memoryview assignment: lvalue and rvalue have different structures
>>>v[2:6] = b'spam'
>>>data
bytearray(b'z1spam')
格式符为 'B', 'b' 或 'c' 的 hashable (只读) 类型的一维内存视图也是可哈希对象。 哈希被定义为 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
如果所指向的内容的值相等,则两个内存视图就相等,并不一定是指向同一片内存视图
>>>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
。
将缓冲区中的数据作为字节串返回。 这相当于在内存视图上调用 bytes 构造器。
>>>m = memoryview(b"abc")
>>>m.tobytes()
b'abc'
>>>bytes(m)
b'abc'
3.8 新版功能: order 可以为 {'C', 'F', 'A'}。 当 order 为 'C' 或 'F' 时,原始数组的数据会被转换至 C 或 Fortran 顺序。 对于连续视图,'A' 会返回物理内存的精确副本。 特别地,内存中的 Fortran 顺序会被保留。对于非连续视图,数据会先被转换为 C 形式。 order=None 与 order='C' 是相同的。
返回一个字符串对象,其中分别以两个十六进制数码表示缓冲区里的每个字节。
在 3.8 版更改: 与 bytes.hex() 相似, memoryview.hex() 现在支持可选的 sep 和 bytes_per_sep 参数以在十六进制输出的字节之间插入分隔符。
将缓冲区内的数据以一个元素列表的形式返回。
>>>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]
返回 memoryview 对象的只读版本。 原始的 memoryview 对象不会被改变。
>>>m = memoryview(bytearray(b'abc'))
>>>mm = m.toreadonly()
>>>mm.tolist()
[97, 98, 99]
>>>mm[0] = 42
Traceback (most recent call last):
File "", line 1, in
TypeError: cannot modify read-only memory
>>>m[0] = 43
>>>mm.tolist()
[43, 98, 99]
释放由内存视图对象所公开的底层缓冲区。 许多对象在被视图所获取时都会采取特殊动作(例如,bytearray 将会暂时禁止调整大小);因此,调用 release() 可以方便地尽早去除这些限制(并释放任何多余的资源)。
在此方法被调用后,任何对视图的进一步操作将引发 ValueError (release() 本身除外,它可以被多次调用):
>>>m = memoryview(b'abc')
>>>m.release()
>>>m[0]
Traceback (most recent call last):
File "", line 1, in
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 "", line 1, in
ValueError: operation forbidden on released memoryview object
将内存视图转化为新的格式或形状。 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):
...
TypeError: memoryview: invalid type 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 long 转换为 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]]
内存视图的下层对象:
>>>b = bytearray(b'xyz')
>>>m = memoryview(b)
>>>m.obj is b
True
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
一个表明内存是否只读的布尔值。
一个字符串,包含视图中每个元素的格式(表示为 struct 模块样式)。 内存视图可以从具有任意格式字符串的导出器创建,但某些方法 (例如 tolist()) 仅限于原生的单元素格式。
在 3.3 版更改: 格式 'B' 现在会按照 struct 模块语法来处理。 这意味着 memoryview(b'abc')[0] == b'abc'[0] == 97。
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 的长度值给出内存所代表的 N 维数组的形状。
在 3.3 版更改: 当 ndim = 0 时值为空元组而不再为 None。
一个整数元组,通过 ndim 的长度给出以字节表示的大小,以便访问数组中每个维度上的每个元素。
在 3.3 版更改: 当 ndim = 0 时值为空元组而不再为 None。
供 PIL 风格的数组内部使用。 该值仅作为参考信息。
一个表明内存是否为 C-contiguous 的布尔值。
3.3 新版功能.
一个表明内存是否为 Fortran contiguous 的布尔值。
3.3 新版功能.
一个表明内存是否为 contiguous 的布尔值。
3.3 新版功能.
这个模块定义了标准 Python 编解码器(编码器和解码器)的基类并提供对内部 Python 编解码器注册表的访问,该注册表负责管理编解码器和错误处理的查找过程。 大多数标准编解码器都属于 文本编码格式,它们可将文本编码为字节串(以及将字节串解码为文本),但也提供了一些将文本编码为文本,以及将字节串编码为字节串的编解码器。 自定义编解码器可以在任意类型间进行编码和解码,但某些模块特性被限制为仅适用于 文本编码格式 或将数据编码为 bytes 的编解码器。
字符串在系统内部存储为 U+0000
--U+10FFFF
范围内的码位序列。
一旦字符串对象要在 CPU 和内存以外使用,字节的大小端顺序和字节数组的存储方式就成为一个影响因素。 如同使用其他编解码器一样,将字符串序列化为字节序列被称为 编码,而从字节序列重建字符串被称为 解码。
Python 自带了许多内置的编解码器,它们的实现或者是通过 C 函数,或者是通过映射表。并提供了一些常见别名以及编码格式通常针对的语言。 别名和语言列表都不是详尽无遗的。有些常见编码格式可以绕过编解码器查找机制来提升性能。 这些优化机会对于 CPython 来说仅能通过一组有限的别名(大小写不敏感)来识别:utf-8, utf8, latin-1, latin1, iso-8859-1, iso8859-1, mbcs (Windows 专属), ascii, us-ascii, utf-16, utf16, utf-32, utf32, 也包括使用下划线替代连字符的的形式。 使用这些编码格式的其他别名可能会导致更慢的执行速度。
常见的中文相关编码:
编码 |
别名 |
语言 |
---|---|---|
ascii |
646, us-ascii |
英语 |
big5 |
big5-tw, csbig5 |
繁体中文 |
big5hkscs |
big5-hkscs, hkscs |
繁体中文 |
gb2312 |
chinese, csiso58gb231280, euc-cn, euccn, eucgb2312-cn, gb2312-1980, gb2312-80, iso-ir-58 |
简体中文 |
gbk |
936, cp936, ms936 |
统一汉语 |
gb18030 |
gb18030-2000 |
统一汉语 |
hz |
hzgb, hz-gb, hz-gb-2312 |
简体中文 |
utf_32 |
U32, utf32 |
所有语言 |
utf_32_be |
UTF-32BE |
所有语言 |
utf_32_le |
UTF-32LE |
所有语言 |
utf_16 |
U16, utf16 |
所有语言 |
utf_16_be |
UTF-16BE |
所有语言 |
utf_16_le |
UTF-16LE |
所有语言 |
utf_7 |
U7, unicode-1-1-utf-7 |
所有语言 |
utf_8 |
U8, UTF, utf8, cp65001 |
所有语言 |
utf_8_sig |
所有语言 |
以下编解码器提供了二进制转换: bytes-like object 到 bytes 的映射。 它们不被 bytes.decode() 所支持(该方法只生成 str 类型的输出)。
编码 |
别名 |
含意 |
编码器/解码器 |
---|---|---|---|
base64_codec 1 |
base64, base_64 |
将操作数转换为多行 MIME base64 (结果总是包含一个末尾的 在 3.4 版更改: 接受任意 bytes-like object作为输入用于编码和解码 |
base64.encodebytes()/ base64.decodebytes() |
bz2_codec |
bz2 |
使用bz2压缩操作数 |
bz2.compress() / bz2.decompress() |
hex_codec |
hex |
将操作数转换为十六进制表示,每个字节有两位数 |
binascii.b2a_hex() / binascii.a2b_hex() |
quopri_codec |
quopri, quotedprintable, quoted_printable |
将操作数转换为 MIME 带引号的可打印数据 |
quopri.encode() 且 quotetabs=True / quopri.decode() |
uu_codec |
uu |
使用uuencode转换操作数 |
uu.encode() / uu.decode() |
zlib_codec |
zip, zlib |
使用gzip压缩操作数 |
zlib.compress() / zlib.decompress() |
使用为 encoding 注册的编解码器对 obj 进行编码。
可以给定 Errors 以设置所需要的错误处理方案。 默认的错误处理方案 'strict' 表示编码错误将引发 ValueError (或更特定编解码器相关的子类,例如 UnicodeEncodeError)。
使用为 encoding 注册的编解码器对 obj 进行解码。
语法格式为:
codecs.open(filename, mode='r', encoding=None, errors='strict', buffering=- 1)
使用给定的 mode 打开已编码的文件并返回一个 StreamReaderWriter 的实例,提供透明的编码/解码。 默认的文件模式为 'r',表示以读取模式打开文件。
encoding 指定文件所要使用的编码格式。 允许任何编码为字节串或从字节串解码的编码格式,而文件方法所支持的数据类型则取决于所使用的编解码器。
可以指定 errors 来定义错误处理方案。 默认值 'strict' 表示在出现编码错误时引发 ValueError。
buffering 的含义与内置 open() 函数中的相同。 默认值 -1 表示将使用默认的缓冲区大小。
语法为:
codecs.EncodedFile(file, data_encoding, file_encoding=None, errors='strict')
返回一个 StreamRecoder 实例,它提供了 file 的透明转码包装版本。 当包装版本被关闭时原始文件也会被关闭。
写入已包装文件的数据会根据给定的 data_encoding 解码,然后以使用 file_encoding 的字节形式写入原始文件。 从原始文件读取的字节串将根据 file_encoding 解码,其结果将使用 data_encoding 进行编码。
如果 file_encoding 未给定,则默认为 data_encoding。
可以指定 errors 来定义错误处理方案。 默认值 'strict' 表示在出现编码错误时引发 ValueError。
使用增量式编码器通过迭代来编码由 iterator 所提供的输入。 此函数属于 生成器(generator)。 errors 参数(以及任何其他关键字参数)会被传递给增量式编码器。
此函数要求编解码器接受 str 对象形式的文本进行编码。 因此它不支持字节到字节的编码器,例如 base64_codec。
使用增量式解码器通过迭代来解码由 iterator 所提供的输入。 此函数属于生成器( generator)。 errors 参数(以及任何其他关键字参数)会被传递给增量式解码器。
此函数要求编解码器接受 bytes 对象进行解码。 因此它不支持文本到文本的编码器,例如 rot_13,但是 rot_13 可以通过同样效果的 iterencode() 来使用。
在 Python 编解码器注册表中查找编解码器信息,并返回一个 CodecInfo 对象。
语法为:
class codecs.CodecInfo(encode, decode, streamreader=None, streamwriter=None, incrementalencoder=None, incrementaldecoder=None, name=None)
编解码器细节信息
查找给定编码的编解码器并返回其编码器函数。
查找给定编码的编解码器并返回其解码器函数。
查找给定编码的编解码器并返回其增量式编码器类或工厂函数。
查找给定编码的编解码器并返回其增量式解码器类或工厂函数。
查找给定编码的编解码器并返回其StreamReader 类或工厂函数。
查找给定编码的编解码器并返回其 StreamWriter类或工厂函数。
注册一个编解码器搜索函数。 搜索函数预期接收一个参数,即全部以小写字母表示的编码格式名称,其中中连字符和空格会被转换为下划线,并返回一个 CodecInfo 对象。 在搜索函数无法找到给定编码格式的情况下,它应当返回 None。
在 3.9 版更改: 连字符和空格会被转换为下划线。
注销一个编解码器搜索函数并清空注册表缓存。 如果指定搜索函数未被注册,则不做任何操作。
在名称 name 之下注册错误处理函数 error_handler。 当 name 被指定为错误形参时,error_handler 参数所指定的对象将在编码和解码期间发生错误的情况下被调用,
对于编码操作,将会调用 error_handler 并传入一个 UnicodeEncodeError 实例,其中包含有关错误位置的信息。 错误处理程序必须引发此异常或别的异常,或者也可以返回一个元组,其中包含输入的不可编码部分的替换对象,以及应当继续进行编码的位置。 替换对象可以为 str 或 bytes 类型。 如果替换对象为字节串,编码器将简单地将其复制到输出缓冲区。 如果替换对象为字符串,编码器将对替换对象进行编码。 对原始输入的编码操作会在指定位置继续进行。 负的位置值将被视为相对于输入字符串的末尾。 如果结果位置超出范围则将引发 IndexError。
解码和转换的做法很相似,不同之处在于将把 UnicodeDecodeError 或 UnicodeTranslateError 传给处理程序,并且来自错误处理程序的替换对象将被直接放入输出。