在处理unicode问题时,我发现unicode(self)
和self.__unicode__()
有不同的行为:
#-*- coding:utf-8 -*-
import sys
import dis
class test():
def __unicode__(self):
s = u'中文'
return s.encode('utf-8')
def __str__(self):
return self.__unicode__()
print dis.dis(test)
a = test()
print a
上面的代码工作正常,但是如果我将
self.__unicode__()
更改为unicode(self)
,它将显示错误:UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
有问题的代码是:
#-*- coding:utf-8 -*-
import sys
import dis
class test():
def __unicode__(self):
s = u'中文'
return s.encode('utf-8')
def __str__(self):
return unicode(self)
print dis.dis(test)
a = test()
print a
很好奇python是如何处理这个问题的,我尝试了dis模块,但没有看到太多的区别:
Disassembly of __str__:
12 0 LOAD_FAST 0 (self)
3 LOAD_ATTR 0 (__unicode__)
6 CALL_FUNCTION 0
9 RETURN_VALUE
对
Disassembly of __str__:
10 0 LOAD_GLOBAL 0 (unicode)
3 LOAD_FAST 0 (self)
6 CALL_FUNCTION 1
9 RETURN_VALUE
最佳答案
s = u'中文'
return s.encode('utf-8')
这将返回一个非Unicode字节字符串这就是
encode
所做的。utf-8并不是神奇地将数据转换成unicode的东西;如果有什么不同的话,那就是用字节(数据,或多或少)表示unicode(一种抽象)的方法。我们需要一些术语。编码就是采用Unicode字符串,并使用某种编码方式生成表示该字符串的字节字符串解码是相反的:取一个字节字符串(我们认为它编码一个unicode字符串),并使用指定的编码将其解释为unicode字符串。
当我们编码成一个字节字符串,然后使用相同的编码进行解码时,我们会得到原始的Unicode。
utf-8
是一种可能的编码。有很多,更多。有时,当您调用
UnicodeDecodeError
时,python会报告一个encode
。为什么?因为你试图encode
一个字节字符串此过程的正确输入是unicode字符串,因此python“有用地”尝试先将字节字符串decode
转换为unicode。但它不知道使用什么编解码器,所以它假定ascii
。这种编解码器是最安全的选择,在这样的环境中,您可以接收各种数据。它只报告一个字节>=128的错误,这些字节在各种8位编码中以无数种不同的方式处理(还记得在一天以前,试图将一个带有é
等字母的word文件从mac导入到pc,或者反之亦然吗?你会在另一台电脑上看到一些奇怪的符号,因为平台内置的编码方式不同。)使事情变得更加复杂,在python 2中,
encode
/decode
机制还用于实现一些与解释unicode无关的其他整洁的事情。例如,有一个Base64编码器,一个可以自动处理字符串转义序列的东西(即,它将把一个反斜杠,后面跟着一个字母“t”,变成一个制表符)其中一些执行从字节字符串到字节字符串或从Unicode到Unicode的“编码”或“解码”。(顺便说一下,在Python3中,这一切的工作方式完全不同——更清楚地说,是IMHO。)
类似地,当
__unicode__
返回一个字节字符串(就样式而言,它不应该这样做)时,python内置函数会自动将其解码为unicode()
;当ascii
返回一个unicode字符串(同样不应该这样做)时,__str__
会将其编码为str()
。这发生在幕后,在代码中你无法控制。但是,您可以修复ascii
和__unicode__
以执行它们应该执行的操作。(实际上,您可以通过传递第二个参数来重写
__str__
的编码。但是,这是错误的解决方案,因为您应该已经有一个从unicode
返回的Unicode字符串而且__unicode__
不接受编码参数,所以你在那里运气不好。)所以,现在我们可以解决这个问题了。
问题:我们希望
str
返回unicode字符串__unicode__
,并且希望u'中文'
返回该字符串的__str__
编码版本。解决方案:直接在
utf-8
中返回该字符串,并在__unicode__
中显式执行编码:class test():
def __unicode__(self):
return u'中文'
def __str__(self):
return unicode(self).encode('utf-8')