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

gar*_*arh 29 python unicode base64 encoding python-3.x

目的base64.b64encode()是将二进制数据转换为ASCII安全"文本".但是,该方法返回一个bytes类型的对象:

>>> import base64
>>> base64.b64encode(b'abc')
b'YWJj'
Run Code Online (Sandbox Code Playgroud)

简单地接受输出就很容易decode(),但我的问题是:base64.b64encode()返回的意义是什么,bytes而不是str

wim*_*wim 24

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

Python不同意这一点 - base64被故意归类为二进制变换.

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

语言采用的意见是bytestring对象已经被编码.将字节编码为文本的编解码器不适合这种范例,因为当你想从字节域转到文本域时,它就是一个解码.请注意,出于同样的原因,rot13编码也从标准编码列表中消失了- 它不适合Python 3范例.

还可以有一个性能参数:假设Python自动处理base64输出的解码,base64输出是由模块的C代码生成的ASCII编码二进制表示binascii,到文本域中的Python对象.如果你真的想要字节,你只需要通过再次编码为ASCII来撤销解码.这将是一次浪费的往返,一次不必要的双重否定.最好"选择加入"解码到文本的步骤.

  • 从某种意义上说,base64 编码是纯文本的,根据定义,仅包含 ASCII,这意味着它的目的是“将二进制数据转换为文本表示形式”。我看不出 Python 实现产生字节的任何原因。字节和文本的分离本身非常有用,但在这种情况下,我个人认为,如果在这种情况下代码不适合这种范式,那么根本不应该应用这种范式。 (6认同)
  • 我想说,您99.99%的时间都希望将其作为字符串,这应该是默认值。如果您关心性能或其他细微差别,可以调用另一个函数。 (3认同)
  • 我认为“将字节编码为文本的编解码器不适合这种范式,因为当您想从字节域转到文本域时,它是一种解码”为我解释了这一点。因此,孤立地看,它可能没有完全的意义,但本着使所有 encode()/decode() 方法具有统一输入/输出的精神,这是有道理的。我还是觉得有点奇怪:) (2认同)

Zer*_*eus 20

b64encode()要知道你想要对它的输出做什么是不可能的.

虽然在许多情况下您可能希望将编码值视为文本,但在许多其他情况下 - 例如,通过网络发送 - 您可能希望将其视为字节.

既然b64encode()不知道,就拒绝猜测.并且由于输入是bytes,输出保持相同类型,而不是被隐式强制转换str.

正如您所指出的,将输出解码str为直接:

base64.b64encode(b'abc').decode('ascii')
Run Code Online (Sandbox Code Playgroud)

......以及对结果的明确表述.

顺便说一句,这是值得注意的是,虽然base64.b64decode()(注:代码,不)已接受str自3.3版本中,变化是一定的争议.

  • 感谢您的回答,不过我对这个解释有一点疑问,潜在的输出总是可以用 ascii 字符串表示,从某种意义上来说,它是 bytes 对象的子集。我认为如果可能的话,您应该以更窄的类型返回结果,字节对象可以是任何东西。一般来说,如果你有一个函数,你将不知道如何处理输出,你仍然希望以有意义的描述性方式返回它,否则所有函数都应该只返回字节,我们应该取消 str 类型。 (2认同)
  • 换句话说,b64encode() 总是知道输出可以表示为 str,那为什么不返回 str 呢? (2认同)
  • 请注意,“为什么不返回一个 str 呢?”之间没有区别。和“那为什么不返回一个字节对象呢?” ...它必须选择*某物*,并且`bytes`被认为最符合应该避免隐式强制的原则。 (2认同)
  • 还要注意,`str`*绝对不是*`bytes`的子集,或者比`bytes`更窄:前者由多达 1,114,112 个不同的代码点组成,而后者只能表示 256 个不同的状态(可能是整数、字符, 或者是其他东西)。ASCII 恰好可以在两者的一个子集中表示,就像 base64 字母表一样,但没有内在的理由假设一个比另一个更自然。 (2认同)
  • @Code-Apprentice 我的思路是“如果您有有关返回数据的附加信息,请提供它”,并且该方法的输出将始终处于此类信息的 ascii 安全范围内。选择称之为“狭隘”可能是一个糟糕的用词。否则,我们总是可以为所有内容返回字节对象,因为所有数据都可以表示为原始字节 - 但这可能不是很有用。 (2认同)