以utf-8声明的模块中的Python Unicode字符串字面值

6

我有一个带有UTF-8头部的虚拟Python模块,其代码如下:

# -*- coding: utf-8 -*-
a = "á"
print type(a), a

这将输出:

<type 'str'> á

但是我认为在Python模块中声明的所有字符串文字都应该自动成为unicode类型,而不是str类型。我错过了什么还是这是正确的行为?

为了将a作为Unicode字符串获取,我使用:

a = u"á"

但这似乎不太“礼貌”,也不实用。有更好的选择吗?

1
使用Python 3代替,所有字符串都将是Unicode。 - Mark Ransom
@MarkRansom 我不能改变Python版本,因为存在兼容性问题。 - Caumons
使用u'...'unicode字面量有什么不得体的地方?你为什么感觉它不实用? - Martijn Pieters
好的,结论是当你需要Unicode字面量时,你必须要“生成”它们,或者用u声明它们。标题编码适用于这些Unicode字符串实际上如何编码,但不影响str - Caumons
5
from __future__ import unicode_literals会将所有的字面值转换为Unicode字面值(适用于Python2.6和2.7)。 - Sven Marnach
显示剩余2条评论
3个回答

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

不会将字符串字面量转换为Unicode。以这个例子为例,我有一个带有阿拉伯语注释和字符串的文件,该文件是utf-8编码:

# هذا تعليق عربي
print type('نص عربي')

如果我运行它,它会抛出一个SyntaxError异常:

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

所以为了允许这一点,我必须添加那行代码来告诉解释器该文件是UTF-8编码的:
# -*-coding: utf-8 -*-

# هذا تعليق عربي
print type('نص عربي')

现在程序已经正常运行,但是除非我把字符串转换成Unicode格式,否则它仍会打印出<type 'str'>
# -*-coding: utf-8 -*-

# هذا تعليق عربي
print type(u'نص عربي')

即使使用文件编码可以使非 ASCII 的 str 正常打印,但处理这些类型的字符串会导致运行时错误,不是吗?因此,如果使用非 ASCII 字符,除了标题之外,始终使用 u 处理潜在冲突的字符串。我说得对吗? - Caumons
@Caumons 如果不是Unicode,它就不会被正确地打印或处理,一个字符被视为两个不同的字符,print len(u'أ'); print len('أ') - user1129665
好的,从现在开始使用 u :) 谢谢! - Caumons

5
不,顶部的编解码器仅告诉Python如何解释源代码,并使用该编解码器来解释Unicode文字。它不会将字面意义的字节串转换为Unicode值。正如PEP 263所述:
本PEP提议引入一种语法来声明Python源文件的编码。然后,Python解析器使用给定的编码来解释文件。最重要的是,这增强了源代码中Unicode文字的解释,并使得可以直接在Unicode感知的编辑器中使用例如UTF-8编写Unicode文字。
我强调了这一点。
没有编解码声明,Python无法理解非ASCII字符:
$ cat /tmp/test.py 
example = '☃'
$ python2.7 /tmp/test.py 
  File "/tmp/test.py", line 1
SyntaxError: Non-ASCII character '\xe2' in file /tmp/test.py on line 1, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

如果Python表现符合您的期望,那么您将无法使用包含非ASCII字节值的文字字节串值。
如果您的终端配置为显示UTF-8值,则打印UTF-8编码的字节字符串看起来“正确”,但这只是因为编码匹配的幸运。
获取Unicode值的正确方法是使用Unicode文字或以其他方式生成Unicode(从字节字符串解码,将整数代码点转换为Unicode字符等):
unicode_snowman = '\xe2\x98\x83'.decode('utf8')
unicode_snowman = unichr(0x2603)

在Python 3中,编解码器也适用于变量名的解释,因为您可以在名称中使用ASCII范围之外的字母和数字。 Python 3中的默认编解码器是UTF-8,而Python 2中是ASCII。

2
如果在字节字符串中包含非ASCII字符且没有指定文件编码,将导致语法错误,尽管编码不会以任何方式影响结果字符串。 - Sven Marnach
@SvenMarnach非常感谢您的评论!!!这完全澄清了我的疑惑!:)我会接受这个答案。 - Caumons
@SvenMarnach:没错,尽管字节串本身的值不会根据编解码器设置而改变,但Python在这里非常保守,不会尝试在没有编解码器设置的情况下解析Python源代码。 - Martijn Pieters

2
这只是源代码编码。请参见http://www.python.org/dev/peps/pep-0263/

To define a source code encoding, a magic comment must be placed into the source files either as first or second line in the file, such as:

      # coding=<encoding name>

or (using formats recognized by popular editors)

      #!/usr/bin/python
      # -*- coding: <encoding name> -*-

or

      #!/usr/bin/python
      # vim: set fileencoding=<encoding name> :
这并不意味着所有字面值都是Unicode,只是指出了如何解码Unicode字面值。
应该使用unicode函数或u前缀将字面值设置为Unicode。
注意,在Python3中,所有字符串都是Unicode。

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