为什么在Python中通过字符串声明unicode?

123 投票
5 回答
167854 浏览
提问于 2025-04-16 00:46

我还在学习Python,有个疑问:

在Python 2.6.x中,我通常在文件的开头声明编码,像这样(参考PEP 0263

# -*- coding: utf-8 -*-

之后,我的字符串就可以像平常一样写了:

a = "A normal string without declared Unicode"

但是每次我看到一个Python项目的代码时,发现文件开头并没有声明编码。相反,每个字符串都像这样声明编码:

a = u"A string with declared Unicode"

这有什么区别呢?这样做的目的是什么?我知道Python 2.6.x默认使用ASCII编码,但可以通过文件头的声明来覆盖,那么每个字符串单独声明编码又有什么意义呢?

补充:看来我把文件编码和字符串编码搞混了。谢谢你们的解释 :)

5 个回答

10

这段话的意思是,设置的不是字符串的格式,而是文件的格式。即使有了那个头部信息,"hello" 仍然是一个字节字符串,而不是Unicode字符串。如果你想让它变成Unicode字符串,你需要在每个地方都使用 u"hello"。那个头部信息只是告诉你在读取 .py 文件时应该使用什么格式。

24

正如其他人所说,# coding: 是用来指定源文件保存时的编码方式。下面有一些例子来说明这个问题:

一个以 cp437 编码保存的文件(这是我的控制台编码),但没有声明编码

b = 'über'
u = u'über'
print b,repr(b)
print u,repr(u)

输出结果:

  File "C:\ex.py", line 1
SyntaxError: Non-ASCII character '\x81' in file C:\ex.py on line 1, but no
encoding declared; see http://www.python.org/peps/pep-0263.html for details

在文件中添加了 # coding: cp437 后的输出结果:

über '\x81ber'
über u'\xfcber'

一开始,Python 不知道这个文件的编码,所以对非 ASCII 字符发出了警告。当它知道了编码后,字节字符串就得到了实际在磁盘上的字节。对于 Unicode 字符串,Python 读取了 \x81,知道在 cp437 编码中这个是一个ü,并把它解码成 Unicode 代码点,表示ü的代码是 U+00FC。当字节字符串被打印时,Python 直接把十六进制值 81 发送到控制台。当 Unicode 字符串被打印时,Python 正确地识别了我的控制台编码是 cp437,并把 Unicode ü 转换成 cp437 中的ü的值。

下面是一个以 UTF-8 编码声明和保存的文件的情况:

├╝ber '\xc3\xbcber'
über u'\xfcber'

在 UTF-8 编码中,ü 被编码为十六进制字节 C3 BC,所以字节字符串包含这些字节,但 Unicode 字符串和第一个例子是一样的。Python 读取了这两个字节并正确解码了它们。但是,Python 打印字节字符串时出错了,因为它直接把表示ü的两个 UTF-8 字节发送到了我的 cp437 控制台。

这里的文件声明为 cp437,但实际上是以 UTF-8 保存的:

├╝ber '\xc3\xbcber'
├╝ber u'\u251c\u255dber'

字节字符串仍然得到了磁盘上的字节(UTF-8 的十六进制字节 C3 BC),但它把这些字节解释成了两个 cp437 字符,而不是一个 UTF-8 编码的字符。这两个字符被转换成了 Unicode 代码点,结果打印出来的内容都是错误的。

168

这两者是不同的事情,正如其他人提到的。

当你写上 # -*- coding: utf-8 -*- 时,你是在告诉Python,你保存的源文件是 utf-8 编码。Python 2的默认编码是ASCII,而Python 3的默认编码是 utf-8。这只是影响解释器如何读取文件中的字符。

一般来说,不管编码是什么,把高Unicode字符直接嵌入文件可能都不是个好主意;你可以使用字符串的Unicode转义,这在任何编码下都能用。


当你在字符串前加一个 u,比如 u'This is a string' 这告诉Python编译器这个字符串是Unicode格式,而不是字节。解释器大部分情况下会透明地处理这个问题;最明显的区别是你现在可以在字符串中嵌入Unicode字符(也就是说, u'\u2665' 现在是合法的)。你可以使用 from __future__ import unicode_literals 来让它成为默认设置。

这只适用于Python 2;在Python 3中,默认就是Unicode,如果你想声明一个字节序列,就需要在前面加个 b(比如 b'These are bytes')。

撰写回答