为什么Python 2.x会抛出字符串格式+ unicode的异常?

时间:2014-03-20 15:30:25

标签: python unicode

我有以下代码。最后一行抛出错误。那是为什么?

class Foo(object):

    def __unicode__(self):
        return u'\u6797\u89ba\u6c11\u8b1d\u51b0\u5fc3\u6545\u5c45'

    def __str__(self):
        return self.__unicode__().encode('utf-8')

print "this works %s" % (u'asdf')
print "this works %s" % (Foo(),)
print "this works %s %s" % (Foo(), 'asdf')
print

print "this also works {0} {1}".format(Foo(), u'asdf')
print
print "this should break %s %s" % (Foo(), u'asdf')

错误是" UnicodeDecode错误:' ascii'编解码器不能解码位置18中的字节0xe6:序数不在范围内(128)"

1 个答案:

答案 0 :(得分:3)

当你混合使用unicode和string对象时,Python 2会隐式地尝试将unicode值编码为字符串,它会尝试将字节字符串解码为unicode。

您正在混合unicode,字节字符串和自定义对象,并且您正在触发一系列无法​​混合的编码和解码。

在这种情况下,您的Foo()值会被插值为字符串(str(Foo())被使用),u'asdf'插值会触发模板的解码到目前为止(使用UTF-8 Foo()值)来插入unicode字符串。此解码失败,因为ASCII编解码器无法解码已插入的\xe6\x9e\x97 UTF-8字节序列。

在混合类型之前,您应始终将Unicode值显式编码为字节串或将字节字符串解码为Unicode,因为极端情况很复杂。

明确转换为unicode()有效:

>>> print "this should break %s %s" % (unicode(Foo()), u'asdf')
this should break 林覺民謝冰心故居 asdf

因为输出变成了unicode字符串:

>>> "this should break %s %s" % (unicode(Foo()), u'asdf')
u'this should break \u6797\u89ba\u6c11\u8b1d\u51b0\u5fc3\u6545\u5c45 asdf'

,否则你最终得到一个字节串:

>>> "this should break %s %s" % (Foo(), 'asdf')
'this should break \xe6\x9e\x97\xe8\xa6\xba\xe6\xb0\x91\xe8\xac\x9d\xe5\x86\xb0\xe5\xbf\x83\xe6\x95\x85\xe5\xb1\x85 asdf'

(请注意,asdf也是一个字节字符串。)

或者,使用unicode 模板

>>> u"this should break %s %s" % (Foo(), u'asdf')
u'this should break \u6797\u89ba\u6c11\u8b1d\u51b0\u5fc3\u6545\u5c45 asdf'