我很困惑。考虑一下这段代码的工作方式:
>>> foo = u'Émilie and Juañ are turncoats.'
>>> bar = "foo is %s" % foo
>>> bar
u'foo is \xc3\x89milie and Jua\xc3\xb1 are turncoats.'
这段代码完全不符合我的预期:
>>> try:
... raise Exception(foo)
... except Exception as e:
... foo2 = e
...
>>> bar = "foo2 is %s" % foo2
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
有人可以解释这里发生了什么吗?为什么unicode数据是在普通的unicode字符串中还是存储在Exception对象中?为什么这会解决它:
>>> bar = u"foo2 is %s" % foo2
>>> bar
u'foo2 is \xc3\x89milie and Jua\xc3\xb1 are turncoats.'
我很困惑!谢谢你的帮助!
更新:我的编码伙伴兰德尔为了帮助我而增加了我的困惑!发送增援内容以解释这是如何理解的:
>>> class A:
... def __str__(self): return "string"
... def __unicode__(self): return "unicode"
...
>>> "%s %s" % (u'niño', A())
u'ni\xc3\xb1o unicode'
>>> "%s %s" % (A(), u'niño')
u'string ni\xc3\xb1o'
请注意,此处参数的顺序决定了调用哪个方法!
答案 0 :(得分:10)
如果
format
是Unicode对象,或者使用%s
转换转换的任何对象是Unicode对象,则结果也将是Unicode对象。
foo = u'Émilie and Juañ are turncoats.'
bar = "foo is %s" % foo
这很有效,因为foo
是unicode
个对象。这会导致上述规则生效并生成Unicode字符串。
bar = "foo2 is %s" % foo2
在这种情况下,foo2
是Exception
对象,显然不是unicode
对象。因此,解释器尝试使用您的默认编码将其转换为普通str
。显然,这是ascii
,它不能代表那些字符并且有例外情况。
bar = u"foo2 is %s" % foo2
此处它再次起作用,因为格式字符串是unicode
对象。因此,解释器也会尝试将foo2
转换为unicode
对象,这会成功。
关于兰德尔的问题:这也让我感到惊讶。但是,根据标准,此是(为了便于阅读而重新格式化):
%s
使用str()
转换任何Python对象。如果提供的对象或格式为unicode
字符串,则生成的字符串也将为unicode
。
如何创建这样的unicode
对象不明确。所以两者都是合法的:
__str__
,解码回Unicode字符串,并将其插入输出字符串__unicode__
并将结果直接插入输出字符串Python解释器的混合行为确实很可怕。我认为这是标准中的一个错误。
编辑:引用Python 3.0 changelog,强调我的:
您认为您对二进制数据和Unicode的了解已经发生了变化。
[...]
- 由于哲学的这种变化,几乎所有使用Unicode,编码或二进制数据的代码都很可能必须改变。这种变化是更好的,因为在2.x世界中,有很多错误与混合编码和未编码的文本有关。