在Python 2中,有两种类型的字符代表字符串:strings 和 unicode。默认将 strings 处理为原生的 bytes 类型(8比特值序列),而不是 unicode(Python 3已经把string处理成unicode,bytes就是bytes);而unicode则由Unicode字符堆砌而成。
1 2 3 4 5 6 7 8 9 10 |
>>> str('中') '\xe4\xb8\xad' >>> bytes('中') '\xe4\xb8\xad' >>> type(str('中')) str >>> type(bytes('中')) str |
可以看到Python 2中 strings 等同于 bytes 类型。
Python 3最重要的新特性大概要算是对文本和二进制数据作了更为清晰的区分。文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示。字符串是以字符为单位进行处理的,Bytes类型是以单个字节作为基本元素(8位,取值范围0-255)为单位处理的。Bytes数据类型在所有的操作和使用甚至内置方法上和字符串数据类型基本一样,也是不可变的序列对象。
bytes 对象只负责以二进制字节序列的形式记录所需记录的对象,至于该对象到底表示什么(比如到底是什么字符)则由相应的编码格式解码所决定。我们可以通过调用 bytes() 类(没错,它是类,不是函数)生成 bytes 实例,其值形式为 b’xxxxx’,其中 ‘xxxxx’ 为一至多个转义的十六进制字符串(单个 x 的形式为:\xHH,其中 \x 为小写的十六进制转义字符,HH 为二位十六进制数)组成的序列,每个十六进制数代表一个字节(八位二进制数,取值范围 0-255),对于同一个字符串如果采用不同的编码方式生成 bytes 对象,就会形成不同的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
>>> a = '徐' >>> ord(a) 24464 >>> b = bytes(a, 'utf-8') >>> type(b) #获取b类型(如果是Python2这里是str) <class 'bytes'> >>> print(b) #b表示bytes b'\xe5\xbe\x90' >>> c = bytes(a, 'gb2312') >>> print(c) b'\xd0\xec' |
比如上例中的 a 字符串对象,其十进制 unicode 值为 24464,分别使用 ‘utf-8′ 和 ‘gb2312′ 两种编码格式将其转换成 bytes 对象 b 和 c ,结果 b 和 c 的值是完全不同的,由于基于的编码格式不一致, b 和 c 的长度甚至都不相同,前者有 3 个字节长度,后者有 2 个字节长度:
1 2 |
>>> print(len(b), len(c)) 3 2 |
另外,对于 ASCII 字符串,可以直接使用 b’xxxx’ 赋值创建 bytes 实例,但对于非 ASCII 编码的字符则不能通过这种方式创建 bytes 实例:
1 2 3 4 5 6 7 |
>>> d = b'徐' File "<console>", line 1 SyntaxError: bytes can only contain ASCII literal characters. >>> d = b'ywnds' >>> print(d) b'ywnds' |
由于 bytes 是序列,因此我们可以通过索引或切片访问它的元素:
1 2 3 4 |
>>> d[0] 121 >>> d[0:1] b'y' |
可以发现如果以单个索引的形式访问元素,其会直接返回单个字节的十进制整数,而以序列片段的形式访问时,则返回相应的 bytes 中ASCII索引元素。
对于 bytes 实例,如果需要还原成相应的字符串,则需要借助内置的解码函数 decode(),借助相应的编码格式解码为正常字符串对象,如果采用错误的编码格式解码,则有可能发生错误:
1 2 3 4 5 6 7 8 |
>>> b.decode('utf-8') '徐' >>> c.decode('gb2312') '徐' >>> b.decode('gb2312') Traceback (most recent call last): File "<console>", line 1, in <module> UnicodeDecodeError: 'gb2312' codec can't decode byte 0x90 in position 2: incomplete multibyte sequence |
除来使用内置 bytes 方法可以将字符串转换为指定编码的 bytes 类型外,也可以利用字符串的encode方法解码成bytes,默认为utf-8类型。
1 2 3 4 5 |
>>> b = a.encode('utf-8') >>> type(b) <class 'bytes'> >>> b.decode() '徐' |
对于bytes,我们只要知道在Python 3中某些场合下强制使用,以及它和字符串类型之间的互相转换,其它的基本照抄字符串。
由于字符类型的不同,所以你通常会需要两个工具函数来对这两种情况的字符进行转换,以此来确保输入值符合代码所预期的字符类型。
Python 3中写一个方法,接收str或者bytes,总是来返回str类型的数据。如下:
1 2 3 4 5 6 7 |
def to_str(bytes_or_str): if isinstance(bytes_or_str,bytes): value = bytes_or_str.encode('utf-8') else: value = bytes_or_str # str类型的数据 return value |
同理,我们需要另一个方法,来接收str或bytes ,总是来返回bytes类型的数据。
1 2 3 4 5 6 7 |
def to_bytes(bytes_or_str): if isinstance(bytes_or_str,str): value = bytes_or_str.encode('utf-8') else: value = bytes_or_str # 字节类型的数据 return value |
在Python3中,bytes类型包含的是8个比特值的序列,str是包含Unicode字符串。字节和字符串实例不能同时出现在操作符‘>’ 或者 ‘+’中,这两者无法比较。所以最好使用工具函数来确保程序输入的数据是预期类型。