我们假设您想支持Python 2.7和3.5版本(2.6和3.0至3.2的处理方式略有不同)。
正如您已经阅读的那样,setdefaultencoding
是不建议使用并且在您的情况下实际上不需要。
为了编写跨平台处理unicode文本的代码,一般只需在以下几个地方指定字符串编码:
- 在脚本顶部,在shebang下方添加
# -*- coding: utf-8 -*-
(仅当代码中有带有unicode文本的字符串字面量时)
- 读取输入数据时(例如从文本文件或数据库读取)
- 输出数据时(再次从文本文件或数据库中)
- 在代码中定义字符串字面量时
这是我按照这些规则更改示例的方法:
people = ['Nicholas Gyeney', 'André']
writers = ", ".join(people)
print(writers)
print("Writers: {}".format(writers))
print(type(writers))
print(len(writers))
输出结果为:
<type 'str'>
23
以下是更改的内容:
- 在文件顶部指定文件编码
- 用实际的Unicode字符(
é
)替换\xe9
- 移除
u
前缀
在Python 2.7.12和3.5.2中都很好用。
但要注意,移除u
前缀将使Python使用普通的str
类型而不是unicode
类型(请参见print(type(writers))
输出)。对于utf-8
,它在大多数地方的表现就像一个unicode字符串,但当检查文本长度时,会返回错误的值。在这个例子中,len
返回23
,而实际字符数是22
。这是因为底层类型是str
,它将每个字节都计算为一个字符,但是字符é
实际上应该是两个字节。
换句话说,在输出数据时,这样做可以正常工作(如您的示例所示),但如果要对文本进行字符串操作,则仍然需要使用u
前缀或将数据显式转换为unicode类型。
因此,如果不是因为您的简单示例,最好仍然使用u
前缀。您需要在两个地方添加它:
people = [u'Nicholas Gyeney', u'André']
writers = ", ".join(people)
print(writers)
print(u"Writers: {}".format(writers))
print(type(writers))
print(len(writers))
它的输出结果为:
<type 'unicode'>
22
注意:Python 3.0 中删除了 u
前缀,但为了向后兼容性在 Python 3.3 中重新引入。
有关在 Python 2 中处理 Unicode 文本的所有复杂性的详细说明,请参阅官方文档:Python 2 - Unicode HOWTO。
以下是有关指定文件编码的特殊注释的摘录:
Python 支持使用任何编码编写 Unicode 字面量,但必须声明正在使用的编码方式。这可以通过将一个特殊注释作为源文件的第一行或第二行来实现:
u = u'abcdé' print ord(u[-1])
该语法受到 Emacs 用于指定文件局部变量的表示法的启发。Emacs 支持许多不同的变量,但 Python 只支持 coding
。-*-
符号指示 Emacs 该注释是特殊的;它们在 Python 中没有意义,但是是一种约定。Python 在注释中查找 coding: name
或 coding=name
。
如果您不包含这样的注释,则使用的默认编码将是 ASCII。
如果您获得了书籍 "Learning Python, 5th Edition",我鼓励您阅读第 VIII 部分的第 37 章 "Unicode 和字节字符串"。它详细解释了在 Python 的两个版本中处理 Unicode 文本的方法。
另一个值得一提的细节是,如果格式字符串是 ascii
,format
始终返回 ascii
字符串,无论参数是否为 unicode
。
相反,旧式的 %
格式化如果任何参数为 unicode
,则返回 unicode
字符串。因此,代替写下面这段代码:
print(u"Writers: {}".format(writers))
你可以写出以下代码,不仅较短、美观,而且在Python 2和3上都可行:
print("Writers: %s" % writers)