Python中bytes对象的字符串表示本质是什么?如何还原原始bytes对象?
问题解答
你查到的官方描述是准确的:
如果既未指定encoding参数也未指定errors参数,str(object)将返回
type(object).__str__(object)的结果[...]。
对bytes对象来说,这个__str__返回的不是解码后的字符串,而是专门的调试用表示,具体规则如下:
bytes对象内置字符串表示的实现规则
对bytes对象直接调用不带encoding参数的str()时,返回结果和对bytes对象调用repr()的输出完全一致,遵循固定转换规则:
- 输出整体固定包裹在
b'前缀和收尾的单引号中,符合Python代码中bytes字面量的书写格式 - 字节值落在ASCII可打印范围(0x20~0x7E,即空格到波浪号
~)的字节,直接输出对应的ASCII字符 - 特殊字节做转义处理:
- 常见ASCII控制字符(换行、制表符、回车等)输出为标准短转义序列,比如
\n、\t、\r - 单引号
'、反斜杠\本身会前置反斜杠转义,避免和外层包裹的语法符号冲突 - 其余所有字节统一输出为
\xHH格式,HH为对应字节值的两位小写十六进制数
- 常见ASCII控制字符(换行、制表符、回车等)输出为标准短转义序列,比如
你之前运行代码拿到的结果完全符合这个规则:阿拉伯语字符串用utf-8编码后每个字符对应2个字节,这些字节值都不在ASCII可打印范围,所以全部被转成了\x开头的十六进制转义序列,再套上b'...'的外壳,和你预期的解码结果完全不是一个逻辑。
能否通过该字符串表示还原原始内容
只要拿到的是完整、未被篡改的str(bytes_obj)输出结果,是可以还原原始bytes对象、再进一步解码得到原Unicode字符串的,但绝对不推荐将这种方式作为通用场景下的编解码/序列化方案。
还原方法
因为输出格式完全匹配Python的bytes字面量语法,可以借助标准库ast的literal_eval方法做安全解析,对应你之前的测试case,示例代码如下:
import ast a = "عجائب" a_bytes = a.encode(encoding="utf-8") b = str(a_bytes) # 从字符串还原原始bytes对象 recovered_bytes = ast.literal_eval(b) # 按原编码解码回Unicode字符串 recovered_a = recovered_bytes.decode("utf-8") print(recovered_a == a) # 输出True
不推荐使用的原因
- 这个字符串表示的设计目的是方便开发者调试时查看字节内容,不是为数据传输、持久化场景设计的:非ASCII字节都会被转成4个字符长度的转义序列,数据体积会膨胀数倍,传输和解析效率都很低
- 鲁棒性极差:只要字符串在流转过程中出现一点改动(比如转义符被吞、外层引号丢失、多了空白字符),解析就会直接失败
- 完全不符合Python3的编码设计规范:Python3刻意取消了str和bytes之间的隐式自动转换,就是为了避免Python2时代泛滥的编码乱码问题,bytes转字符串的正确做法永远是显式指定对应编码调用
.decode()方法,比如utf-8编码的字节直接调用a_bytes.decode("utf-8")即可得到预期结果,不要直接对bytes对象调用无参数的str()。
内容的提问来源于stack exchange,提问作者Bernhard
相关产品推荐
相关产品推荐

