在处理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')

10-08 08:45