我们已经在Python 2.6下运行了我们的代码库.为了准备Python 3.0,我们开始添加:
from __future__ import unicode_literals
进入我们的.py
文件(因为我们修改它们).我想知道是否还有其他人这样做并遇到任何非显而易见的陷阱(也许是在花了很多时间调试之后).
我使用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, inprint 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 = 'helló wörld' if isinstance(html, unicode): html = html.encode('utf-8') print 'DEBUG: %s' % html
输出:
DEBUG: helló wörld
但添加后import unicode_literals
它不会:
# encoding: utf-8 from __future__ import unicode_literals html = 'helló wörld' if isinstance(html, unicode): html = html.encode('utf-8') print 'DEBUG: %s' % html
输出:
Traceback (most recent call last): File "test.py", line 6, inprint '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')
.
我希望这可以帮助您了解使用unicode字符串时的潜在问题.
同样在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 "", line 1, in 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, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
还要考虑到unicode_literal
会影响eval()
但不影响repr()
(不对称行为,即imho是一个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+
第二个断言恰好起作用,因为在Python 2.7中repr('\xa4')
进行了评估u'\xa4'
.
还有更多.
有些库和内置函数需要不能容忍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()(我的是)的调用,后者就是毁灭性的.
哇,嗯?!?