它是完全确定性和简单的。不过,您需要注意字节和 unicode 字符串之间的区别。阅读Ned Batchelder 的Pragmatic Unicode。
a
指由三个字符组成的 unicode 字符串,因此a
对其进行评估,Python REPL 会尝试使用print()
它——第一步是将其转换为 a str
(仅return self
用于字符串)。根据与标准输出(例如您的终端)关联的编码,将生成的字符串转换为字节,并将这些字节发送到那里。您的终端根据它使用的编码来解释它接收到的字节。
a.encode('ascii')
使用 ASCII 编码将 unicode 显式转换为字节序列。其结果是一个字节对象,该结果print
由 Python REPL 'd'。同样,第一步是将其转换为字符串——因为字节不是字符串,并且两者之间的隐式转换是非常有害的,正如 Python 2 编码/解码错误所证明的那样,你只会得到repr
同样给你的东西:一个等价的字符串到 Python 源代码中的字节文字。然后像以前一样打印此字符串,相同的区别。
在>>> print(a)
中,您调用print
自己的结果与上述相同,结果print
是None
Python REPL 不会打印它。与>>> print(a.encode('ascii'))
and相同>>> print(str(a.encode('ascii')))
,您只需显式触发打印并str
预先进行转换,而不是隐式进行。
确实存在 的逆str.encode
,它确实被称为decode
并且是bytes
对象的方法。所以some_str.encode(E).decode(E)
可以是无操作的。它还可能丢失信息或沿途更改字符串(例如,通过替换未知字符),或者如果您不要求它丢失信息,则抛出异常。
如果您有以某种编码表示某些字符串的字节,则可以将它们用于 I/O。事实上,这是执行 I/O 的“本机”方式——所有 I/O 和所有网络都是字节。但print
适用于字符串。相反,在文件 I/O(包括标准输出)的情况下,您希望以二进制模式打开它们并使用该.write
方法。具体来说sys.stdout
,默认情况下使用文本模式,但您可以访问二进制版本作为sys.stdout.buffer
. 当然,如果您发送的字节是使用不同的编码创建的(或者根本不打算作为文本),您会得到胡言乱语。