Python中的文本和字节

概述

最近工作中的项目同时使用到了 Python2 和 Python3 ,遇到了文本和字节的 tricks,自己之前对这方面不太了解,学习并总结一下。

编码介绍

Unicode 标准

Unicode 是用于表示文本以供计算机进行处理的通用字符编码标准。Unicode 标准提供了一种对多语种纯文本进行一致编码的方法,便于国际文本文件的交换。

字符 的最佳定义是 Unicode 字符 。Unicode 只是一个符号集,它只规定了符号的二进制代码,并没有规定这个二进制代码应该如何存储。

UTF-8

UTF-8 字符编码是 Unicode 的实现方式之一。

UTF-8 是一种变长的编码方式,它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

Python 中的文本和字节

Python3 中从 str 对象中获取的元素就是 Unicode 字符,可以通过 编码 (encode)文本 转化为 字节

然而 Python2 中从 str 对象中获取的元素是字节序列,只有通过 解码 (decode) 才能将 字节 转化为 文本

下面使用两个版本的 Python 对字符串进行操作以作解释:

1
2
3
4
5
6
7
8
9
# py3
>>> s = '123'
>>> type(s)
<class 'str'> # 文本
>>> b = s.encode('utf-8')
>>> b
b'123'
>>> type(b)
<class 'bytes'> # 字节序列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# py2
>>> s = '123'
>>> type(s)
<type 'str'> # 这里是字节序列
>>> b = s.encode('utf-8')
>>> b
'123'
>>> type(b)
<type 'str'> # 这里还是字节序列
>>> b.decode() # decode 出来的才是文本
u'123'
>>> type(b.decode())
<type 'unicode'> # 文本
>>> c = '一二三'
>>> c
'\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89' # 字节序列

从上面的程序可以总结出 Python2 和 Python3 对于字符串处理上的区别:

Python2 Python3
Unicode strings unicode str
Bytes strings str bytes

Python 中的 u, b, r

Python 的字符串有时候前面会加一个 ur 或者 b ,其含义如下:

u :表示字符串中的元素是 Unicode 字符。结合上面表格的结论,可以认为:在 Python3 中,字符串前面是否加 u 的效果是一致的。在 Python2 中,字符串前面加 u 表示其中的元素是 Unicode 字符,不加 u 表示 bytes。

b :表示字符串中的元素是 Bytes。同结合上面表格的结论,可以认为:在 Python2 中,字符串前面是否加 b 的效果是一致的。在 Python3 中,字符串前面加 b 表示其中的元素是 bytes,不加 b 表示 Unicode 字符。

r :表示字符串是 原始字符串(raw string) ,里面的字符都是 raw string literals ,与 Unicode 和 Bytes 无关,因此 Python2 和 Python3 中含义是一致的。它的作用是使解释器不会对诸如 \n, \t 等转义字符进行转义:

1
2
3
4
5
6
7
# py3
>>> s1 = '123\n123\t123'
>>> s1
'123\n123\t123'
>>> s2 = r'123\n123\t123'
>>> s2
'123\\n123\\t123' # 不转义

Python2 和 Python3 在字符串处理方面的兼容

既然 Python2 和 Python3 在字符串的处理方面有所不同,但是实际工作中却需要写出兼容两种版本的代码,那么应该如何处理呢?

我的做法是使用 __future__ 模块:

1
from __future__ import unicode_literals

该模块的作用是将 Python2 的字符串字面量的类型变为文本,而不是字节,因此与 Python3 是一样的。

举个栗子:

1
2
3
4
5
6
7
8
9
10
11
12
# py2
>>> from __future__ import unicode_literals
>>> s = '123'
>>> s
u'123'
>>> type(s)
<type 'unicode'> # 文本
>>> b = b'123'
>>> b
'123'
>>> type(b)
<type 'str'> # 字节

总结

目前 Python2 与 Python3 是并存的,因此在编写代码过程中需要注意其中的差异和兼容性,不然就要出锅了hhh(虽然 Python2 在 2020 年 1 月就要停止维护了)。

参考