str和unicode是python2的老话题了。我这个从3学到2的人还真不太适应,今天补习了一下,发现说法还真多。

首先str和unicode的区别是什么呢?str相当于单byte数组,而unicode存的是UCS-2或UCS-4。可以敲一下

>>> sys.maxunicode

如果是65535(0xffff)就是UCS-2,如果是1114111(0x10ffff)就是UCS-4。

然后其实可以把str看成编码过的信息,把unicode看成抽象的未经编码的文本信息(虽然其实是UCS-2/UCS-4)。

这么看的话unicode的encode和str的decode就说得通了。unicode的encode就是把抽象的文本编码一下,变成具体的,str的decode正好反过来。下面的实验证实了这一点:

>>> a = '你好'
>>> b = u'你好'

>>> a
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> b
u'\u4f60\u597d'

>>> b.encode('UTF-8')
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> a.decode('UTF-8')
u'\u4f60\u597d'

很通顺是吧。然后现在我告诉你unicode还可以decode,str还可以encode你作何感想?试一下:

>>> b.decode('UTF-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

>>> a.encode('UTF-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

大侠,为什么我decode却出现了UnicodeEncodeError,encode却出现了UnicodeDecodeError?

先说后面那个。a.encode()相当于unicode(a).encode()。调用unicode构造函数时没有指定编码,所以采用默认编码。python2.x的默认编码是ascii。不信敲个sys.getdefaultencoding()看看。然后就不用说了吧。b.decode()那个是一样的,就是反过来了。

至于允许这么做有用没用,反正python3里已经没有这些玩意儿了,有用没用好像还是挺明显的。总之,就老老实实地在str上调用decode,在unicode上调用encode吧。

这里插一个ipython的bug,差点让我误入歧途。在ipython里输入

In [1]: b = u'你好'

得到的是

In [2]: b
Out[2]: u'\xe4\xbd\xa0\xe5\xa5\xbd'

真囧。

最后顺带展望一下python3的美好。没有神马unicode了,没有默认ascii这回事了,新的组合叫str/bytes。默认编码UTF-8,而且str默认就支持unicode字符,而bytes就是一个纯字节数组。这样区分就很明显了,要表示抽象的字符串,就用str;要表示编码过的字符串,就用bytes。str只能encode,bytes只能decode,没有那么多乱糟糟的事了。

Links: