为什么Python有时会将字符串升级为unicode,有时不会?

sam*_*gar 2 python unicode

我糊涂了.考虑一下这段代码的工作方式:

>>> foo = u'Émilie and Juañ are turncoats.'
>>> bar = "foo is %s" % foo
>>> bar
u'foo is \xc3\x89milie and Jua\xc3\xb1 are turncoats.'
Run Code Online (Sandbox Code Playgroud)

而且这段代码完全没有按照我期望的方式工作:

>>> 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)
Run Code Online (Sandbox Code Playgroud)

有人能解释一下这里发生了什么吗?为什么unicode数据是在普通的unicode字符串中还是存储在Exception对象中?为什么这会解决它:

>>> bar = u"foo2 is %s" % foo2
>>> bar
u'foo2 is \xc3\x89milie and Jua\xc3\xb1 are turncoats.'
Run Code Online (Sandbox Code Playgroud)

我很困惑!谢谢您的帮助!

更新:我的编码伙伴Randall加入了我的困惑,试图帮助我!发送增援内容以解释这是如何理解的:

>>> 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'
Run Code Online (Sandbox Code Playgroud)

请注意,这里参数的顺序决定了调用哪个方法!

Tho*_*mas 10

Python语言参考了答案:

如果format是Unicode对象,或者使用%s转换转换的任何对象是Unicode对象,则结果也将是Unicode对象.

foo = u'Émilie and Juañ are turncoats.'
bar = "foo is %s" % foo
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为它foo是一个unicode对象.这会导致上述规则生效并生成Unicode字符串.

bar = "foo2 is %s" % foo2
Run Code Online (Sandbox Code Playgroud)

在这种情况下,foo2是一个Exception对象,它显然不是一个unicode对象.因此,解释器尝试str使用您的默认编码将其转换为法线.显然,这是ascii,它不能代表那些角色,并且有例外.

bar = u"foo2 is %s" % foo2
Run Code Online (Sandbox Code Playgroud)

这里它再次起作用,因为格式字符串是一个unicode对象.所以解释器也试图转换foo2为一个unicode成功的对象.


至于兰德尔的问题:这也让我感到惊讶.但是,这根据标准(为了可读性而重新格式化):

%s 使用转换任何Python对象str().如果提供的对象或格式是unicode字符串,则结果字符串也将是unicode.

如何unicode创建这样的对象还不清楚.所以两者都是合法的:

  • 调用__str__,解码回Unicode字符串,并将其插入输出字符串
  • 调用__unicode__并将结果直接插入输出字符串

Python解释器的混合行为确实很可怕.我认为这是标准中的一个错误.

编辑:引用Python 3.0更改日志,强调我的:

你认为你对二进制数据和Unicode知道的一切都发生了变化.

[...]

  • 由于哲学上的这种变化,几乎所有使用Unicode,编码或二进制数据的代码都很可能必须改变.变化是更好的,因为在2.x世界中有许多错误与混合编码和未编码的文本有关.