为什么base64.b64encode()返回一个字节对象?

55
< p > base64.b64encode() 的目的是将二进制数据转换为 ASCII 安全的“文本”。不过,该方法返回一种字节类型的对象:

>>> import base64
>>> base64.b64encode(b'abc')
b'YWJj'

简单来说,我们可以使用 decode() 方法对文本进行解码,但我的问题是:为什么 base64.b64encode() 返回的是 bytes 而不是 str

2个回答

34

b64encode() 不知道你想如何处理它的输出。

虽然在很多情况下你可能会把编码后的值看作文本,但在其他情况下,例如发送到网络上时,你可能需要将其视为字节。

b64encode() 无法猜测,因此它拒绝尝试。由于输入是 bytes,所以输出保持相同类型,而不会被隐式强制转换为 str

正如你指出的那样,将输出解码为 str 是简单的:

base64.b64encode(b'abc').decode('ascii')

同时还需明确结果。

值得一提的是,尽管base64.b64decode()(注意:decode而不是encode)自3.3版本以来已经接受了str,但这个更改曾经引起争议


2
谢谢回答,但我对这个解释有些疑问。潜在的输出总是可以用ASCII字符串表示,这在某种意义上是字节对象的子集。我认为,如果可能的话,你应该返回更窄的类型结果,因为字节对象可以是任何东西。通常,如果你有一个函数,你不知道输出会被用来做什么,你仍然希望以一种有意义的描述方式返回它,否则所有函数都应该只返回字节,并且我们应该放弃str类型。 - gardarh
2
换句话说,b64encode() 总是知道输出可以表示为 str,那么为什么不直接返回一个 str 呢? - gardarh
2
请注意,“为什么不返回一个字符串?”和“为什么不返回一个字节对象?”之间没有区别……它必须选择某些东西,而bytes被认为是最符合隐式强制转换应该被避免的原则的。 - Zero Piraeus
4
请注意,str 绝对不是 bytes 的子集或者比 bytes 更窄:前者由多达 1,114,112 种不同的代码点组成,而后者只能表示 256 种不同的状态(可以是整数、字符或其他)。ASCII 恰好可以用两者的一个子集来表示,base64 字母表也是如此,但没有固有的理由认为其中一个比另一个更符合自然。 - Zero Piraeus
2
@Code-Apprentice 我的想法是“如果您有关于返回数据的其他信息,请提供”,而且该方法的输出始终在ASCII安全范围内,因为这种信息。选择称其为“narrow”可能是措辞不当。否则,我们可以针对所有内容始终返回字节对象,因为所有数据都可以表示为原始字节 - 但这可能没有什么用处。 - gardarh
显示剩余7条评论

33

base64.b64encode()函数的目的是将二进制数据转换为ASCII安全的“文本”。

Python不赞同这一点 - base64已经被有意地归类为二进制转换

在Python 3中,强制分离字节和文本并禁止隐式转换是一项设计决策。Python现在对此非常严格,以至于bytes.encode甚至不存在,因此b'abc'.encode('base64')会引发一个AttributeError

语言的观点是,一个字节串对象已经被编码了。将字节转换为文本的编解码器不符合这种范式,因为当你想从字节域转换到文本域时,需要进行解码。请注意,由于相同的原因,rot13编码也被从标准编码列表中驱逐出去了 - 它不能很好地适应Python 3的范式。

还可以提出一个性能论点:假设Python自动处理了base64输出的解码,这是C代码从binascii模块产生的ASCII编码的二进制表示,转换为文本域中的Python对象。如果你实际上需要的是字节,那么你只需要通过再次进行ASCII编码来撤销解码即可。这将是一个浪费时间的往返操作,一个不必要的双重否定。最好选择“选择加入”解码到文本步骤。


2
我认为“将字节编码为文本的编解码器不适合这种范式,因为当你想从字节域转换到文本域时,它是一个解码”的解释对我很有帮助。因此,在孤立的情况下,它可能并不完全合理,但在使所有encode()/decode()方法具有统一的输入/输出的精神下,它是有意义的。我仍然觉得它有点奇怪 :) - gardarh
15
我认为99.99%的情况下你需要将它作为一个字符串处理,并且这应该是默认设置。在你关心性能或其他细节的情况下,你可以调用另一个函数。 - syvex
6
从本质上讲,Base64编码纯文本,ASCII限定,这意味着它的目的是将二进制数据转换为文本表示。我看不出Python实现产生字节的任何原因。字节和文本的分离在某种程度上非常有用,但在这种情况下,个人认为如果在这种情况下代码不适合这种范例,那么就不应该采用这种范例。 - Anthony

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接