在Python 2.6中使用unicode_literals的任何陷阱?

时间:2009-05-01 00:56:37

标签: python unicode python-2.6 unicode-literals

我们已经在Python 2.6下运行了我们的代码库。为了准备Python 3.0,我们开始添加:

from __future__ import unicode_literals

到我们的.py文件中(因为我们修改它们)。我想知道是否还有其他人这样做并且遇到了任何非显而易见的陷阱(可能是在花了很多时间调试之后)。

6 个答案:

答案 0 :(得分:101)

我使用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_literalsone.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') % htmlprint 'DEBUG: %s' % html.decode('utf-8')

我希望这有助于您了解使用unicode字符串时的潜在问题。

答案 1 :(得分:16)

同样在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

答案 2 :(得分:13)

我确实发现如果你添加unicode_literals指令,你还应该添加如下内容:

 # -*- coding: utf-8

到你的.py文件的第一行或第二行。否则行如:

 foo = "barré"

会导致错误,例如:

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

答案 3 :(得分:8)

还要考虑unicode_literal会影响eval()而不影响repr()(imho是一个错误的非对称行为),即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')在Python 2.7中评估为u'\xa4'

答案 4 :(得分:5)

还有更多。

有些库和内置函数需要不能容忍unicode的字符串。

两个例子:

内建:

myenum = type('Enum', (), enum)

(略带esotic)不适用于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()的调用(后者是),则后者是毁灭性的。

该死,呃?!?

答案 5 :(得分:0)

Click will raise unicode exceptions all over the place,如果任何具有from __future__ import unicode_literals的模块被导入到您使用click.echo的位置。这是一场噩梦……