101

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

从 __future__ 导入 unicode_literals

到我们的.py文件中(当我们修改它们时)。我想知道是否有其他人一直在这样做并且遇到了任何不明显的问题(可能是在花了很多时间调试之后)。

4

6 回答 6

101

我在使用 unicode 字符串时遇到的问题的主要来源是当您将 utf-8 编码字符串与 unicode 字符串混合时。

例如,考虑以下脚本。

二.py

# encoding: utf-8
name = 'helló wörld from two'

一个.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),因为它没有 import 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') % htmlprint 'DEBUG: %s' % html.decode('utf-8').

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

于 2009-05-05T23:52:06.657 回答
16

同样在 2.6(python 2.6.5 RC1+ 之前)中,unicode 文字不能很好地与关键字参数(issue4978)配合使用:

例如,以下代码可以在没有 unicode_literals 的情况下工作,但会因 TypeError 失败:keywords must be string如果使用 unicode_literals。

  >>> 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
于 2009-11-24T10:10:01.817 回答
13

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

 # -*- coding: utf-8

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

 foo = "barré"

导致错误,例如:

SyntaxError:第 198 行的文件 mumble.py 中的非 ASCII 字符“\xc3”,
 但没有声明编码;见http://www.python.org/peps/pep-0263.html
 详情
于 2009-05-05T20:09:56.817 回答
7

还要考虑到unicode_literal会影响eval()但不会影响repr()(恕我直言是一个错误的不对称行为),即eval(repr(b'\xa4'))不等于b'\xa4'(就像 Python 3 那样)。

理想情况下,以下代码将是一个不变量,它应该始终适用于unicode_literalsPython {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+

第二个断言恰好起作用,因为在 Python 2.7 中repr('\xa4')计算为。u'\xa4'

于 2010-10-21T11:51:19.223 回答
5

还有更多。

有一些库和内置函数需要不容忍 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() 的调用(我的就是这样),后者是毁灭性的。

该死的,嗯?!?

于 2013-09-18T12:48:43.330 回答
0

from __future__ import unicode_literals如果在您使用的地方导入了任何模块,Click 将在所有地方引发 unicode 异常click.echo。这是一场噩梦……</p>

于 2019-01-24T09:53:39.213 回答