跳至主要内容

如何在 Python 中将字节(bytes)转换为字符串(string)

要在 Python 中将字节转换为字符串,可以使用 .decode() 方法,并指定合适的编码。
· 8分钟 阅读

使用 AI 探索

Python 中一个不太为人熟知的内置序列是 bytes,它是由整数构成的不可变序列。每个整数代表一个字节的数据。数据经常以字节的形式在网络和程序之间传输。字节对人类并不友好可读,我们常常需要在 Python 程序中把它们转换为字符串。

本教程将介绍在 Python 中将字节转换为字符串的方法。如果您对相反的操作感兴趣,请查看我的教程如何在 Python 中将字符串转换为字节。

着急的读者可以先看下面的简短答案。

简短答案:如何在 Python 中将字节转换为字符串

在 Python 中,将字节转换为字符串的主要工具是 .decode() 方法:

data = b"\xc3\xa9clair"
text = data.decode(encoding="utf-8")
print(text)
éclair

.decode() 方法返回一个表示该 bytes 对象的字符串。在此示例中使用的是 UTF-8 解码。UTF-8 是默认编码,因此上面的示例中并不必需显式指定,但我们也可以使用其他编码。

理解 Python 中的字节和字符串

Python 内置了 bytes 数据结构,它是一个由 0 到 255 范围内整数构成的不可变序列。这个 256 个数的范围内的任一整数都可以用 8 位数据表示,即一个字节。因此,bytes 对象中的每个元素都是表示一个字节的整数。

让我们用 bytes() 构造函数通过一个列表创建一个 bytes 对象:

data = bytes([68, 97, 116, 97, 67, 97, 109, 112])
print(type(data))
<class 'bytes'>

这组整数是不可变的:

data[0] = 100
Traceback (most recent call last):
 ...
   data[0] = 100
   ~~~~^^^
TypeError: 'bytes' object does not support item assignment

当我们尝试更改该序列中的某个值时,Python 会引发 TypeError。我们再来确认一下,bytes 对象只能包含 0 到 255 范围内的整数:

data = bytes([254, 255, 256])
Traceback (most recent call last):
 ...
   data = bytes([254, 255, 256])
          ^^^^^^^^^^^^^^^^^^^^^^
ValueError: bytes must be in range(0, 256)

ValueError 表明,表示字节的整数必须是 range(0, 256) 的成员。按照 Python 数值范围的惯例,区间的末端是不包含的。

我们可以用 print() 显示 bytes 对象:

data = bytes([68, 97, 116, 97, 67, 97, 109, 112])
print(data)
b'DataCamp'

该表示展示了用字符表示的 bytes 对象。Python 会使用与这些数值对应的ASCII 字符显示这些整数。引号中字符前的前缀 b 表示这是一个 bytes 对象。

我们也可以直接使用字节字面量创建一个 bytes 对象:

data = b"DataCamp"
print(data)
print(data[0])
b'DataCamp'
68

对象以字符的形式显示,但其元素是整数。

然而,只有当使用可打印的 ASCII 字符对应的整数时,bytes 对象才是人类可读的。由于 ASCII 是一种 7 位编码,它包含 128 个码位,但其中只有 95 个 ASCII 字符是可打印的。

介于 0 到 127 之间但没有可打印 ASCII 字符的整数,以及介于 128 到 255 之间的整数,会以十六进制数显示:

data = bytes([0, 68, 97, 116, 97, 67, 97, 109, 112, 200])
print(data)
b'\x00DataCamp\xc8'

列表中的第一个整数现在是 0,它不是 ASCII 中的可打印字符。bytes 对象将其显示为 \x00,即 0 的十六进制表示。最后一个整数是 200,超出 ASCII 范围,但仍在可用于字节的整数范围内。Python 将其显示为 \xc8,即 200 的十六进制形式。

bytes 与字符串这两种数据结构有共同点。它们都是不可变序列,但 bytes 包含的是整数,而字符串包含的是字符:

data = bytes([68, 97, 116, 97, 67, 97, 109, 112])
print(data[0])

​text = "DataCamp"
print(text[0])
68
D

字节用于在网络和不同接口之间传输数据。本文下一节将介绍如何将字节转换为字符串。

将字节转换为字符串:.decode() 方法

在 Python 中,只有当 bytes 对象包含可读的 ASCII 字符时,它才是人类可读的。在大多数应用中,这些字符并不够用。我们可以使用 .decode() 方法将 bytes 对象转换为字符串:

data = bytes([68, 97, 116, 97, 67, 97, 109, 112])
text = data.decode()

print(text)
print(type(text))
DataCamp
<class 'str'>

不过,在字节与字符串之间转换时可以使用不同的编码。上面的示例中,这些整数代表的是可打印的 ASCII 字符。然而,在未向 .decode() 传入参数时使用的默认编码是UTF-8,而不是 ASCII。UTF-8 是用于Unicode 字符的最广泛使用的编码。

UTF-8 的前 128 个码位与 ASCII 一一对应,这就是为什么在上面的示例中,bytes 对象 data 会被解码为字符串 "DataCamp"。

然而,Unicode 收录了将近 150,000 个字符。UTF-8 会使用两个或更多字节来对所有非 ASCII 的 Unicode 字符进行编码。

我们来创建一个新的 bytes 对象并对其进行解码:

data = bytes([195, 169])
print(data)

text = data.decode()
print(text)
b'\xc3\xa9'
é

bytes 对象包含两个字节:整数 195 和 169。Python 显示的是这些字节的十六进制表示。然而,.decode() 使用 UTF-8 编码对该 bytes 对象进行解码并返回字符串。字节对 b'\xc3\xa9' 表示带尖音符的字母 e,即 é。

.decode() 方法接收一个可选参数用于指定编码:

text = data.decode("utf-8")
print(text)
é

UTF-8 是默认编码,但我们也可以使用其他编码。我们还可以通过字符串方法 .encode() 并指定不同编码,将字符串转换为 bytes 对象:

text = "éclair"
data = text.encode("utf-8")
print(data)

data = text.encode("utf-16")
print(data)
b'\xc3\xa9clair'
'b'\xff\xfe\xe9\x00c\x00l\x00a\x00i\x00r\x00''

相同的字符串会根据所用的字符编码不同而转换为不同的 bytes 对象。

编码错误

在字节与字符串之间转换时,如果使用了不同的字符编码,就可能引发错误。我们继续用将字符串 "éclair" 使用 UTF-8 编码为字节的示例:

text = "éclair"
data = text.encode("utf-8")
print(data)
b'\xc3\xa9clair'

这串字节是用 UTF-8 编码来表示字符的。如果我们使用错误的编码,.decode() 方法会引发错误:

text = data.decode("ascii")
print(text)
Traceback (most recent call last):
 ...
   text = data.decode("ascii")
          ^^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

不过,我们可以通过传入可选的 errors 参数来处理这些错误。errors 参数的默认值是 "strict",即遇到无效字符时会引发错误。

可以用 errors="ignore" 调用 .decode() 来忽略所有无效字符:

text = data.decode("ascii", errors="ignore")
print(text)
clair

原始字符串的第一个字符是 é,它不是 ASCII 字符。因此,.decode() 返回的字符串会缺少第一个字符。

另一种选择是使用 errors="replace" 调用 .decode(),它会用 � 替换无效字节:

text = data.decode("ascii", errors="replace")
print(text)
��clair

这个输出表明字符串缺少了某些字符。错误处理策略的选择取决于具体应用。

使用 str() 将字节转换为字符串

.decode() 是将字节转换为字符串的主要方式。不过,也可以直接使用 str() 构造函数。对 bytes 对象使用 str() 构造函数会创建原始字节的字符串表示:

data = b'\xc3\xa9clair'
text = str(data)

print(text)
print(type(text))
b'\xc3\xa9clair'
<class 'str'>

不过,str() 构造函数也接受一个 encoding 参数,我们可以用它根据特定编码创建字符串:

text = str(data, encoding='utf-8')
print(text)
éclair

使用 codecs.decode() 将字节转换为字符串

Python 标准库中的 codecs 模块提供了编码和解码数据的接口。该模块还提供了一个 .decode() 函数,可用于将 Python 字节转换为字符串:

import codecs

​data = b'\xc3\xa9clair'
text = codecs.decode(data, encoding='utf-8')
print(text)
éclair

这些替代转换技术不是 bytes 类型的方法,而是需要将 bytes 对象作为参数传入的函数。

总结

数据通常以字节形式传输,许多 Python 应用需要在字节与字符串之间进行转换。bytes 对象是不可变的字节序列,可以使用多种字符编码将其转换为 string。

将 Python 字节转换为字符串的主要方式是 .decode() 方法,它允许用户选择编码和错误处理策略。

您可以通过以下教程和课程继续学习 Python:

Stephen Gruppetta

作者

Stephen Gruppetta

我在马耳他大学完成了本科阶段的物理与数学学习。随后前往伦敦,并在帝国理工学院取得物理学博士学位,研究用于成像人类视网膜的新型光学技术。现在,我专注于撰写与传播 Python 相关内容,并教授 Python。

主题