编程后端开发工程师

解释在 Python 中内置的 bytes 类型的工作原理和特点。它如何以及在哪里应用,如何与 str 区别,以及在处理二进制数据时需要注意的细节是什么?

用 Hintsage AI 助手通过面试

回答。

问题历史

随着 Python 3 的出现,bytes 类型成为存储和处理二进制数据的主要类型,与字符串 (str) 分开。在 Python 2 中,字符串 (str) 可以包含文本和字节,这导致在处理不同编码的数据时经常出现错误。

问题

在日常编程中,我们常常会遇到在文本信息上下文之外传输和存储数据的任务——例如处理文件、网络请求和交换协议。为此,需要一种明确、方便和安全的类型,清楚地区分字节序列与字符串数据。

解决方案

Python 中的 bytes 类型存储不可变的字节序列(0 到 255 之间的整数)并且可以通过字节文字(带有前缀 b)或通过显式类型转换来创建。为了在字符串 (str) 和字节 (bytes) 之间安全和可预测的交互,使用 .encode().decode() 方法。在处理文件、网络和各种二进制协议时,bytes 是主要选择。

代码示例:

# 创建 bytes 对象 b = b'hello' # 通过文字 b2 = bytes([104, 101, 108, 108, 111]) # 从整数列表 # 转换 str <=> bytes text = '文本' bin_text = text.encode('utf-8') # str -> bytes back = bin_text.decode('utf-8') # bytes -> str # 文件示例 with open('file.bin', 'rb') as f: data = f.read() # data: bytes

关键特点:

  • bytes 是不可变 (immutable) 的字节序列容器。
  • 与 str 的区别:str 存储 (Unicode) 文本,bytes 存储二进制数据。
  • 所有转换操作都需要明确指定编码。

误导性问题。

可以将 bytes 和 str 连接到一个变量吗?

不可以,使用 + 或 f-字符串连接是无效的:如果尝试执行 b'abc' + 'def',将引发 TypeError。需要显式地转换类型。

bytes 和 bytearray 有什么区别?

bytes 是不可变类型,即内容创建后无法更改。bytearray 是可变版本,支持在原地修改字节的方法。

b = bytes([1, 2, 3]) # 不可变 ba = bytearray([1, 2, 3]) # 可变 ba[0] = 99 # OK b[0] = 99 # TypeError

如何知道字符串在通过 encode() 转换时会占用多少字节?

字节数量依赖于编码。例如,对于 'abc' 在 utf-8 中是 3 字节,而 '你好' 是 12 字节。只有在调用 encode() 后,可以通过 len() 来确定准确的大小:

s = '你好' # 2 个字 b = s.encode('utf-8') # 12 字节 print(len(b)) # 12

典型错误和反模式

  • 将 bytes 和 str 混淆,传递字符串到期望字节的地方(例如,HTTP 请求、二进制文件),反之亦然。
  • 忘记在写入文本文件或输出时显式解码字节。
  • 直接比较 bytes 和 str — 总是 False。

实际案例

消极案例

开发者以 'rb'(字节模式)读取文件,并试图直接将其作为字符串处理:

with open('file.txt', 'rb') as f: for line in f: print(line.strip()) # line: bytes

优点:

  • 可能适用于 ASCII 文件。

缺点:

  • 对于 Unicode 文件,没有解码的情况下无法处理。
  • 在尝试与 str 连接时会出现错误。

积极案例

开发者通过 decode() 处理字节流,引入编码控制:

with open('file.txt', 'rb') as f: for line in f: print(line.decode('utf-8').strip())

优点:

  • 代码适用于任何正确编码的文本文件。
  • 在处理和输出时的可预测行为。

缺点:

  • 对显式选择编码增加了额外的责任。
  • 在错误解码时需要额外处理错误。