Python二进制序列类型(二)array、struct和memoryview

Python实用教程_spiritx的博客-CSDN博客

前面一篇学习了bytes和bytearray,这一篇学习其他的两个类型array和memoryview,同时会对struct模块和 codecs进行学习

array

高效的数字数组

此模块定义了一种对象类型,可以紧凑地表示由基本值(字符、整数、浮点数)组成的数组。数组是序列类型,其行为与列表非常相似,不同之处在于其中存储的对象类型是受限的,在数组对象创建时用单个字符的 类型码 来指定。已定义的类型码如下:

类型码

C 类型

Python 类型

以字节为单位的最小大小

备注

'b'

signed char

int

1

'B'

unsigned char

int

1

'u'

wchar_t

Unicode 字符

2

(1)

'h'

signed short

int

2

'H'

unsigned short

int

2

'i'

signed int

int

2

'I'

unsigned int

int

2

'l'

signed long

int

4

'L'

unsigned long

int

4

'q'

signed long long

int

8

'Q'

unsigned long long

int

8

'f'

float

float

4

'd'

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
从Unicode字符串追加数组

array.fromunicode(s)

使用来自给定 Unicode 字符串的数组扩展数组。 数组必须是类型为 'u' 的数组;否则将引发 ValueError。 请使用 array.frombytes(unicodestring.encode(enc)) 来将 Unicode 数据添加到其他类型的数组。

追加一个元素

array.append(x)

添加一个值为 x 的新项到数组末尾。

从iter对象追加素组

array.extend(iterable)

将来自 iterable 的项添加到数组末尾。 如果 iterable 是另一个数组,它必须具有 完全 相同的类型码;否则将引发 TypeError。 如果 iterable 不是一个数组,则它必须为可迭代对象并且其元素必须为可添加到数组的适当类型。

转换为其他对象

转换为字节串

array.tobytes()

将数组转换为一个机器值数组并返回其字节表示(即相当与通过 tofile() 方法写入到文件的字节序列。)

3.2 新版功能: tostring() 被重命名为含义更准确的 tobytes()。

写入文件

array.tofile(f)

将所有项(作为机器值)写入到 file object f。

转换为列表

array.tolist()

将数组转换为包含相同项的普通列表。

转换为Unicode字符串

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。 它适用于从不同字节序机器所生成的文件中读取数据的情况。

struct

字节串数据的打包或解包.

格式串字符

格式串字符描述了打包和拆包时的数据格式,格式字符指定数据类型,特殊字符控制字节顺序、大小端和对齐方式。

字节顺序,大小和对齐方式

格式字符串的第一个字符可用于指示打包数据的字节顺序,大小和对齐方式:

字符

字节顺序

大小

对齐方式

@

按原字节

按原字节

按原字节

=

按原字节

标准

<

小端

标准

>

大端

标准

!

网络(=大端)

标准

如果第一个字符不是其中之一,则假定为 '@' 。

本机大小和对齐方式是使用 C 编译器的 sizeof 表达式来确定的。 这总是会与本机字节顺序相绑定。

请注意 '@' 和 '=' 之间的区别:两个都使用本机字节顺序,但后者的大小和对齐方式是标准化的。

形式 '!' 代表网络字节顺序总是使用在 IETF RFC 1700 中所定义的大端序。

没有什么方式能指定非本机字节顺序(强制字节对调);请正确选择使用 '<' 或 '>'

注释:

  • 填充只会在连续结构成员之间自动添加。 填充不会添加到已编码结构的开头和末尾。
  • 当使用非本机大小和对齐方式即 '<', '>', '=', and '!' 时不会添加任何填充。
  • 要将结构的末尾对齐到符合特定类型的对齐要求,请以该类型代码加重复计数的零作为格式结束。

格式字符

格式字符具有以下含义;C 和 Python 值之间的按其指定类型的转换应当是相当明显的。 ‘标准大小’列是指当使用标准大小时以字节表示的已打包值大小;也就是当格式字符串以 '<''>''!' 或 '=' 之一开头的情况。 当使用本机大小时,已打包值的大小取决于具体的平台。

格式

C 类型

Python 类型

标准大小

备注

x

填充字节

(7)

c

char

长度为 1 的字节串

1

b

signed char

整数

1

(1), (2)

B

unsigned char

整数

1

(2)

?

_Bool

bool

1

(1)

h

short

整数

2

(2)

H

unsigned short

整数

2

(2)

i

int

整数

4

(2)

I

unsigned int

整数

4

(2)

l

long

整数

4

(2)

L

unsigned long

整数

4

(2)

q

long long

整数

8

(2)

Q

unsigned long long

整数

8

(2)

n

ssize_t

整数

(3)

N

size_t

整数

(3)

e

(6)

float

2

(4)

f

float

float

4

(4)

d

double

float

8

(4)

s

char[]

字节串

(9)

p

char[]

字节串

(8)

P

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

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()

语法:

struct.pack(formatv1v2...)

参数说明:

  • format:格式字符串。
  • v1, v2, ..., vn:需要转换为字节串的值。

返回一个 bytes 对象,其中包含根据格式字符串 format 打包的值 v1v2, ... 参数个数必须与格式字符串所要求的值完全匹配。

该函数常用于将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()

语法:

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()

struct.pack_into(formatbufferoffsetv1v2...)

根据格式字符串 format 打包 v1v2, ... 等值并将打包的字节串写入可写缓冲区 buffer 从 offset 开始的位置。 请注意 offset 是必需的参数。

struct.unpack_from()

语法:

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 : <ctypes.c_char_Array_36 object at 0x106b98c20>
Packed Value : 2205000049206c6f766520796f750000560e49404e6f21476f20617761792100bc010000
Unpacked Type : <class 'tuple'>  Value: (1314, b'I love you', 3.1414999961853027, b'No!Go away!', 444)
‘''

struct.iter_unpack(formatbuffer)

根据格式串format从缓冲区buffer解包,结果为一个迭代器。

struct.calcsize(format)

返回与格式字符串 format 相对应的结构的大小(亦即 pack(format, ...) 所产生的字节串对象的大小)。

memoryview

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]
<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' 的 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

__eq__(exporter)

如果所指向的内容的值相等,则两个内存视图就相等,并不一定是指向同一片内存视图

>>>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

tobytes(order='C')

将缓冲区中的数据作为字节串返回。 这相当于在内存视图上调用 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' 是相同的。

hex([sep[, bytes_per_sep]])

返回一个字符串对象,其中分别以两个十六进制数码表示缓冲区里的每个字节。

在 3.8 版更改: 与 bytes.hex() 相似, memoryview.hex() 现在支持可选的 sep 和 bytes_per_sep 参数以在十六进制输出的字节之间插入分隔符。

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]

toreadonly()

返回 memoryview 对象的只读版本。 原始的 memoryview 对象不会被改变。

>>>m = memoryview(bytearray(b'abc'))
>>>mm = m.toreadonly()
>>>mm.tolist()
[97, 98, 99]
>>>mm[0] = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot modify read-only memory
>>>m[0] = 43
>>>mm.tolist()
[43, 98, 99]

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

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):
  ...
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]]

obj

内存视图的下层对象:

>>>b  = bytearray(b'xyz')
>>>m = memoryview(b)
>>>m.obj is b
True

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

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 新版功能.

codecs

这个模块定义了标准 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 (结果总是包含一个末尾的 '\n')

在 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()​​​​​​​

codecs.encode(objencoding='utf-8'errors='strict')

使用为 encoding 注册的编解码器对 obj 进行编码。

可以给定 Errors 以设置所需要的错误处理方案。 默认的错误处理方案 'strict' 表示编码错误将引发 ValueError (或更特定编解码器相关的子类,例如 UnicodeEncodeError)。

codecs.decode(objencoding='utf-8'errors='strict')

使用为 encoding 注册的编解码器对 obj 进行解码。

codecs.open()

语法格式为:

codecs.open(filenamemode='r'encoding=Noneerrors='strict'buffering=- 1)

使用给定的 mode 打开已编码的文件并返回一个 StreamReaderWriter 的实例,提供透明的编码/解码。 默认的文件模式为 'r',表示以读取模式打开文件。

encoding 指定文件所要使用的编码格式。 允许任何编码为字节串或从字节串解码的编码格式,而文件方法所支持的数据类型则取决于所使用的编解码器。

可以指定 errors 来定义错误处理方案。 默认值 'strict' 表示在出现编码错误时引发 ValueError。

buffering 的含义与内置 open() 函数中的相同。 默认值 -1 表示将使用默认的缓冲区大小。

codecs.EncodedFile()

语法为:

codecs.EncodedFile(filedata_encodingfile_encoding=Noneerrors='strict')

返回一个 StreamRecoder 实例,它提供了 file 的透明转码包装版本。 当包装版本被关闭时原始文件也会被关闭。

写入已包装文件的数据会根据给定的 data_encoding 解码,然后以使用 file_encoding 的字节形式写入原始文件。 从原始文件读取的字节串将根据 file_encoding 解码,其结果将使用 data_encoding 进行编码。

如果 file_encoding 未给定,则默认为 data_encoding。

可以指定 errors 来定义错误处理方案。 默认值 'strict' 表示在出现编码错误时引发 ValueError。

codecs.iterencode(iterator, encoding, errors='strict', **kwargs)

使用增量式编码器通过迭代来编码由 iterator 所提供的输入。 此函数属于 生成器(generator)。 errors 参数(以及任何其他关键字参数)会被传递给增量式编码器。

此函数要求编解码器接受 str 对象形式的文本进行编码。 因此它不支持字节到字节的编码器,例如 base64_codec。

codecs.iterdecode(iterator, encoding, errors='strict', **kwargs)

使用增量式解码器通过迭代来解码由 iterator 所提供的输入。 此函数属于生成器( generator)。 errors 参数(以及任何其他关键字参数)会被传递给增量式解码器。

此函数要求编解码器接受 bytes 对象进行解码。 因此它不支持文本到文本的编码器,例如 rot_13,但是 rot_13 可以通过同样效果的 iterencode() 来使用。

codecs.lookup(encoding)

在 Python 编解码器注册表中查找编解码器信息,并返回一个 CodecInfo 对象。

class codecs.CodecInfo()

语法为:

class codecs.CodecInfo(encodedecodestreamreader=Nonestreamwriter=Noneincrementalencoder=Noneincrementaldecoder=Nonename=None)

编解码器细节信息

  • name: 编码名称
  • encode、decode:无状态的编码和解码函数。 它们必须是具有与 Codec 的 encode() 和 decode() 方法相同接口的函数或方法。 这些函数或方法应当工作于无状态的模式。
  • incrementalencoder、incrementaldecoder:增量式的编码器和解码器类或工厂函数。 这些函数必须分别提供由基类 IncrementalEncoder 和 IncrementalDecoder 所定义的接口。 增量式编解码器可以保持状态。
  • streamwriter、streamreader:流式写入器和读取器类或工厂函数。 这些函数必须分别提供由基类 StreamWriter 和 StreamReader 所定义的接口。 流式编解码器可以保持状态。

codecs.getencoder(encoding)

查找给定编码的编解码器并返回其编码器函数。

codecs.getdecoder(encoding)

查找给定编码的编解码器并返回其解码器函数。

codecs.getincrementalencoder(encoding)

查找给定编码的编解码器并返回其增量式编码器类或工厂函数。

codecs.getincrementaldecoder(encoding)

查找给定编码的编解码器并返回其增量式解码器类或工厂函数。

codecs.getreader(encoding)

查找给定编码的编解码器并返回其StreamReader 类或工厂函数。

codecs.getwriter(encoding)

查找给定编码的编解码器并返回其 StreamWriter类或工厂函数。

codecs.register(search_function)

注册一个编解码器搜索函数。 搜索函数预期接收一个参数,即全部以小写字母表示的编码格式名称,其中中连字符和空格会被转换为下划线,并返回一个 CodecInfo 对象。 在搜索函数无法找到给定编码格式的情况下,它应当返回 None。

在 3.9 版更改: 连字符和空格会被转换为下划线。

codecs.unregister(search_function)

注销一个编解码器搜索函数并清空注册表缓存。 如果指定搜索函数未被注册,则不做任何操作。

codecs.register_error(nameerror_handler)

在名称 name 之下注册错误处理函数 error_handler。 当 name 被指定为错误形参时,error_handler 参数所指定的对象将在编码和解码期间发生错误的情况下被调用,

对于编码操作,将会调用 error_handler 并传入一个 UnicodeEncodeError 实例,其中包含有关错误位置的信息。 错误处理程序必须引发此异常或别的异常,或者也可以返回一个元组,其中包含输入的不可编码部分的替换对象,以及应当继续进行编码的位置。 替换对象可以为 str 或 bytes 类型。 如果替换对象为字节串,编码器将简单地将其复制到输出缓冲区。 如果替换对象为字符串,编码器将对替换对象进行编码。 对原始输入的编码操作会在指定位置继续进行。 负的位置值将被视为相对于输入字符串的末尾。 如果结果位置超出范围则将引发 IndexError。

解码和转换的做法很相似,不同之处在于将把 UnicodeDecodeError 或 UnicodeTranslateError 传给处理程序,并且来自错误处理程序的替换对象将被直接放入输出。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值