努力理解 Python 输出(Unicode、UTF-8、不同的 Python 版本)

Struggling to understand Python Output (Unicode, UTF-8, different Python Versions)

环境设置

我正在使用默认编码 UTF-8 的 iTerm2。

1/ 混乱

启动 Python2.7 解释器,我不明白为什么我们看到看似相同功能的两个不同输出:

>>> print('你好') 
你好

### vs

>>> '你好'
'\xe4\xbd\xa0\xe5\xa5\xbd'

我认为简单地按回车键会隐式调用 print() 函数 - 为什么我们观察到不同的输出?我在这里缺少哪些中间步骤?

2/ 混乱

另一方面,相同的代码在不同的 python 版本中会产生不同的输出:

Python2.7

>>> print('\xe4\xbd\xa0\xe5\xa5\xbd')
你好

Python3

>>> print('\xe4\xbd\xa0\xe5\xa5\xbd')
你好

有人可以解释为什么会这样吗?我猜想 Python2.7 将二进制文件按原样转发到标准输出,这可能是 UTF-8 相当于你好。那么 Python3 有什么不同之处呢?

我认为终端输出、shell 环境和字符串编码之间存在一些相互作用,我不太了解 python 版本不同。我理解 UTF-8、Unicode、ASCII,但无法将它们连接在一起。

谢谢!

  1. print 输出对象的 str() 表示。如果交互式解释器中没有 print,则输出对象的 repr() 表示。对于字符串,repr() 是一个调试输出,带有用于不可打印、非 ASCII 字符的转义码;而 str() 输出是“漂亮的”。

    类 可以指定它们的 repr()str() 格式。示例:

    >>> class Test:
    ...   def __repr__(self):
    ...     return 'repr_of_Test'
    ...   def __str__(self):
    ...     return 'str_of_Test'
    ...
    >>> t = Test()
    >>> t
    repr_of_Test
    >>> print(t)
    str_of_Test
    
  2. Python 2.7 str类型实际上等同于Python 3 bytes类型。字节直接写入终端并以终端默认编码进行解释。请注意,字符串中的字节是 UTF-8,因为您的源文件是用 UTF-8 编写的,或者您的终端使用的是 UTF-8。在支持中文的 Windows 控制台上,您将获得在活动代码页中编码的字节:

    C:\>chcp 936
    Active code page: 936
    
    C:\>py -2
    Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:22:17) [MSC v.1500 32 bit (Intel)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> '你好'
    '\xc4\xe3\xba\xc3'
    

    Python 3 str类型是Unicode字符串,然后在输出时以默认终端编码进行编码(注意,Python 3的更高版本在Windows将使用 Windows Unicode API 直接写入 Windows cmd.exe 终端,而不使用默认编码。

    所以你的 Python 2.7 print 将 UTF-8 编码的字节直接发送到终端,在那里它们被解释为 UTF-8,而你的 Python 3 示例解释每个转义代码作为 Unicode 代码点。例如 '\xe4' 实际上是 Unicode U+00E4 ä(带分音符的拉丁文小写字母 A),这正是打印的内容。为您的中文打印 Unicode 代码点,它将正常工作。

    >>> print('\u4f60\u597d')
    你好
    

    与Python2相比,这比依赖于用户代码页才能正常工作的字节串更加一致。