返回介绍

4.2 字节概要

发布于 2024-02-05 21:59:48 字数 5033 浏览 0 评论 0 收藏 0

新的二进制序列类型在很多方面与 Python 2 的 str 类型不同。首先要知道,Python 内置了两种基本的二进制序列类型:Python 3 引入的不可变 bytes 类型和 Python 2.6 添加的可变 bytearray 类型。(Python 2.6 也引入了 bytes 类型,但那只不过是 str 类型的别名,与 Python 3 的 bytes 类型不同。)

bytes 或 bytearray 对象的各个元素是介于 0~255(含)之间的整数,而不像 Python 2 的 str 对象那样是单个的字符。然而,二进制序列的切片始终是同一类型的二进制序列,包括长度为 1 的切片,如示例 4-2 所示。

示例 4-2 包含 5 个字节的 bytes 和 bytearray 对象

>>> cafe = bytes('café', encoding='utf_8') ➊
>>> cafe
b'caf\xc3\xa9'
>>> cafe[0] ➋
99
>>> cafe[:1] ➌
b'c'
>>> cafe_arr = bytearray(cafe)
>>> cafe_arr ➍
bytearray(b'caf\xc3\xa9')
>>> cafe_arr[-1:] ➎
bytearray(b'\xa9')

❶ bytes 对象可以从 str 对象使用给定的编码构建。

❷ 各个元素是 range(256) 内的整数。

❸ bytes 对象的切片还是 bytes 对象,即使是只有一个字节的切片。

❹ bytearray 对象没有字面量句法,而是以 bytearray() 和字节序列字面量参数的形式显示。

❺ bytearray 对象的切片还是 bytearray 对象。

 my_bytes[0] 获取的是一个整数,而 my_bytes[:1] 返回的是一个长度为 1 的 bytes 对象——这一点应该不会让人意外。s[0] == s[:1] 只对 str 这个序列类型成立。不过,str 类型的这个行为十分罕见。对其他各个序列类型来说,s[i] 返回一个元素,而 s[i:i+1] 返回一个相同类型的序列,里面是 s[i] 元素。

虽然二进制序列其实是整数序列,但是它们的字面量表示法表明其中有 ASCII 文本。因此,各个字节的值可能会使用下列三种不同的方式显示。

可打印的 ASCII 范围内的字节(从空格到 ~),使用 ASCII 字符本身。

制表符、换行符、回车符和 \ 对应的字节,使用转义序列 \t、\n、\r 和 \\。

其他字节的值,使用十六进制转义序列(例如,\x00 是空字节)。

因此,在示例 4-2 中,我们看到的是 b'caf\xc3\xa9':前 3 个字节 b'caf' 在可打印的 ASCII 范围内,后两个字节则不然。

除了格式化方法(format 和 format_map)和几个处理 Unicode 数据的方法(包括 casefold、isdecimal、isidentifier、isnumeric、isprintable 和 encode)之外,str 类型的其他方法都支持 bytes 和 bytearray 类型。这意味着,我们可以使用熟悉的字符串方法处理二进制序列,如 endswith、replace、strip、translate、upper 等,只有少数几个其他方法的参数是 bytes 对象,而不是 str 对象。此外,如果正则表达式编译自二进制序列而不是字符串,re 模块中的正则表达式函数也能处理二进制序列。Python 3.0~3.4 不能使用 % 运算符处理二进制序列,但是根据“PEP 461—Adding % formatting to bytes and bytearray”,Python 3.5 应该会支持。

二进制序列有个类方法是 str 没有的,名为 fromhex,它的作用是解析十六进制数字对(数字对之间的空格是可选的),构建二进制序列:

>>> bytes.fromhex('31 4B CE A9')
b'1K\xce\xa9'

构建 bytes 或 bytearray 实例还可以调用各自的构造方法,传入下述参数。

一个 str 对象和一个 encoding 关键字参数。

一个可迭代对象,提供 0~255 之间的数值。

一个整数,使用空字节创建对应长度的二进制序列。[Python 3.5 会把这个构造方法标记为“过时的”,Python 3.6 会将其删除。参见“PEP 467—Minor API improvements for binary sequences”。]

一个实现了缓冲协议的对象(如 bytes、bytearray、memoryview、array.array);此时,把源对象中的字节序列复制到新建的二进制序列中。

使用缓冲类对象构建二进制序列是一种低层操作,可能涉及类型转换。示例 4-3 做了演示。

示例 4-3 使用数组中的原始数据初始化 bytes 对象

>>> import array
>>> numbers = array.array('h', [-2, -1, 0, 1, 2]) ➊
>>> octets = bytes(numbers) ➋
>>> octets
b'\xfe\xff\xff\xff\x00\x00\x01\x00\x02\x00' ➌

➊ 指定类型代码 h,创建一个短整数(16 位)数组。

➋ octets 保存组成 numbers 的字节序列的副本。

➌ 这些是表示那 5 个短整数的 10 个字节。

使用缓冲类对象创建 bytes 或 bytearray 对象时,始终复制源对象中的字节序列。与之相反,memoryview 对象允许在二进制数据结构之间共享内存。如果想从二进制序列中提取结构化信息,struct 模块是重要的工具。下一节会使用这个模块处理 bytes 和 memoryview 对象。

结构体和内存视图

struct 模块提供了一些函数,把打包的字节序列转换成不同类型字段组成的元组,还有一些函数用于执行反向转换,把元组转换成打包的字节序列。struct 模块能处理 bytes、bytearray 和 memoryview 对象。

如 2.9.2 节所述,memoryview 类不是用于创建或存储字节序列的,而是共享内存,让你访问其他二进制序列、打包的数组和缓冲中的数据切片,而无需复制字节序列,例如 Python Imaging Library(PIL)2 就是这样处理图像的。

2Pillow 是 PIL 最活跃的派生库。

示例 4-4 展示了如何使用 memoryview 和 struct 提取一个 GIF 图像的宽度和高度。

示例 4-4 使用 memoryview 和 struct 查看一个 GIF 图像的首部

>>> import struct
>>> fmt = '<3s3sHH'  # ➊
>>> with open('filter.gif', 'rb') as fp:
...   img = memoryview(fp.read())  # ➋
...
>>> header = img[:10]  # ➌
>>> bytes(header)  # ➍
b'GIF89a+\x02\xe6\x00'
>>> struct.unpack(fmt, header)  # ➎
(b'GIF', b'89a', 555, 230)
>>> del header  # ➏
>>> del img

❶ 结构体的格式:< 是小字节序,3s3s 是两个 3 字节序列,HH 是两个 16 位二进制整数。

❷ 使用内存中的文件内容创建一个 memoryview 对象……

❸ ……然后使用它的切片再创建一个 memoryview 对象;这里不会复制字节序列。

❹ 转换成字节序列,这只是为了显示;这里复制了 10 字节。

❺ 拆包 memoryview 对象,得到一个元组,包含类型、版本、宽度和高度。

❻ 删除引用,释放 memoryview 实例所占的内存。

注意,memoryview 对象的切片是一个新 memoryview 对象,而且不会复制字节序列。 [本书的技术审校之一 Leonardo Rochael 指出,如果使用 mmap 模块把图像打开为内存映射文件,那么会复制少量字节。本书不会讨论 mmap,如果你经常读取和修改二进制文件,可以阅读“mmap—Memory-mapped file support”来进一步学习。]

本书不会深入介绍 memoryview 和 struct 模块,如果要处理二进制数据,可以阅读它们的文档:“Built-in Types » Memory Views”和“struct—Interpret bytes as packed binary data”。

简要探讨 Python 的二进制序列类型之后,下面说明如何在它们和字符串之间转换。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文