我们已经让我们的代码在 Python 2.6 下运行。为了准备 Python 3.0,我们开始在修改 .py 文件时添加:
from __future__ import unicode_literals我想知道是否有其他人也这样做,并且是否遇到过任何非明显的问题(可能是经过长时间调试后才发现的)。
from __future__ import unicode_literals我想知道是否有其他人也这样做,并且是否遇到过任何非明显的问题(可能是经过长时间调试后才发现的)。
我在处理Unicode字符串时,主要遇到的问题是将UTF-8编码的字符串与Unicode字符串混合使用。
例如,请考虑以下脚本。
two.py
# encoding: utf-8
name = 'helló wörld from two'
one.py
# encoding: utf-8
from __future__ import unicode_literals
import two
name = 'helló wörld from one'
print name + two.name
python one.py
的输出结果为:Traceback (most recent call last):
File "one.py", line 5, in <module>
print name + two.name
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)
two.name
是一个utf-8编码的字符串(不是unicode),因为它没有导入unicode_literals
,而one.name
是一个unicode字符串。当你混合使用两者时,Python会尝试解码编码的字符串(假设它是ascii)并将其转换为unicode,但会失败。如果你执行print name + two.name.decode('utf-8')
,就可以解决这个问题。# encoding: utf-8
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
html = html.encode('utf-8')
print 'DEBUG: %s' % html
输出:
DEBUG: <html><body>helló wörld</body></html>
import unicode_literals
之后,它就不会:# encoding: utf-8
from __future__ import unicode_literals
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
html = html.encode('utf-8')
print 'DEBUG: %s' % html
输出:
Traceback (most recent call last):
File "test.py", line 6, in <module>
print 'DEBUG: %s' % html
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 16: ordinal not in range(128)
'DEBUG: %s'
是一个unicode字符串,因此Python尝试解码html
。修复打印的几种方法是:要么执行print str('DEBUG: %s') % html
,要么执行print 'DEBUG: %s' % html.decode('utf-8')
。在Python 2.6中(在Python 2.6.5 RC1+之前),unicode字面量与关键字参数不兼容(issue4978):
例如,下面的代码在没有使用unicode_literals的情况下可以正常工作,但是如果使用了unicode_literals,则会出现TypeError: keywords must be string
错误。
>>> def foo(a=None): pass
...
>>> foo(**{'a':1})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
我发现如果你添加了unicode_literals
指令,你还应该添加类似于:
# -*- coding: utf-8
将以下内容添加到您的 .py 文件的第一行或第二行。否则,类似以下行:
foo = "barré"
会导致错误,例如:
SyntaxError: Non-ASCII character '\xc3' in file mumble.py on line 198, 但未声明编码;参见 http://www.python.org/peps/pep-0263.html 了解详情
unicode_literals
或不使用它的情况下,我认为# -*- coding: utf-8
这条语句几乎是必须的。 - MestreLion-*-
不是必需的;如果你想要兼容emacs的方式,我认为你需要 -*- encoding: utf-8 -*-
(注意末尾的 -*-
)。你只需要 coding: utf-8
(甚至可以用 =
代替 :
)。 - Chris Morganfrom __future__ import unicode_literals
,您都会收到此错误。 - Flimmunicode_literal
将会影响 eval()
而不是 repr()
(这种不对称的行为在我看来是一个 bug),即 eval(repr(b'\xa4'))
不等于 b'\xa4'
(与 Python 3 中应该相等)。unicode_literals
和 Python {2.7, 3.x} 的用法都应该有效:from __future__ import unicode_literals
bstr = b'\xa4'
assert eval(repr(bstr)) == bstr # fails in Python 2.7, holds in 3.1+
ustr = '\xa4'
assert eval(repr(ustr)) == ustr # holds in Python 2.7 and 3.1+
repr('\xa4')
的计算结果为u'\xa4'
。还有更多。
有一些库和内置函数需要的是不支持unicode编码的字符串。
以下举两个例子:
内置函数:
myenum = type('Enum', (), enum)
(稍微有些奇怪的)在使用unicode_literals时无法工作:type()需要一个字符串。
库:
from wx.lib.pubsub import pub
pub.sendMessage("LOG MESSAGE", msg="no go for unicode literals")
无法正常工作:wx pubsub库需要一个字符串消息类型。
前者很深奥,并且可以很容易地通过以下方式进行修复:
myenum = type(b'Enum', (), enum)
但是如果你的代码中充满了对 pub.sendMessage() 的调用(我的就是),后者会使情况变得严重。
真是让人沮丧啊!
class Meta:
中声明的任何字符串都应该是 b'field_name'
。 - Hamish Downer点击会在各处引发Unicode异常,如果您在使用click.echo
的地方导入了任何带有from __future__ import unicode_literals
的模块。这是一场噩梦...
decode()
解决方案而不是str()
或encode()
解决方案:您越经常使用Unicode对象,代码就会更清晰,因为您想要操作的是字符字符串,而不是带有外部隐含编码的字节数组。 - Eric O. Lebigotwhen you mix utf-8 encoded strings with unicode ones
UTF-8 和 Unicode 不是两种不同的编码方式;Unicode 是一种标准,而 UTF-8 是它定义的其中一种编码方式。 - Kosstr
类型,后者属于unicode
类型。由于它们是不同的对象,如果您尝试将它们相加/连接/插值,可能会出现问题。 - MestreLionpython>=2.6
还是python==2.6
? - joar