str是字符数据,bytes和bytearray是字节数据。它们都是序列,能够进行迭代遍历。str和bytes是不可变序列,bytearray是可变序列,能够原处修改字节。html
bytes和bytearray都能使用str类型的通用函数,好比find()、replace()、islower()等,不能用的是str的格式化操做。因此,若有须要,参考字符串(string)方法整理来获取这些函数的使用方法。python
str将各个字符组合在一块儿,以一种不可变序列进行存储。可是在底层它仍是一个个的二进制数,是由一个个的字节组成的(也就是byte),只不过python根据指定的字符集编码"强行"将字节序列显示为字符。编辑器
python 3.x中默认str是unicode格式编码的,例如UTF-8字符集。ide
>>> import sys >>> sys.getdefaultencoding() 'utf-8'
unicode编码的str,意味着可以直接存储除ascii码外的不少字符,好比中文,好比欧洲的重音符号。还意味着能够将一个unicode字符存储为多个字节,并将连续多个的字节翻译成单个对应的字符。函数
>>> a = "我" >>> a '我' >>> ord(a) 25105 >>> a.encode() b'\xe6\x88\x91'
根据指定字符集,底层的字节序列和字符序列间的转换过程彻底无需人为的参与,python已经作好了一切。工具
bytes是不可变的二进制格式字节数据(注意,是字节不是字符),以整数方式表示。例如对于ascii范围内的字符"a",它存储为97。编码
要构造bytes类型的数据,方法之一是在字符串前面加上b或B前缀。翻译
例如:设计
>>> B = b"abcd" >>> [i for i in B] [97, 98, 99, 100] >>> B[0] = "A" Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'bytes' object does not support item assignment
bytes和下面的bytearray都能使用str类型的绝大部分方法。例如find()、replace()等,但用法上可能会有所区别,好比str.replace()的替换参数期待的是字符,而bytes.replace()的替换参数多是字节。例如:code
>>> b'abcd'.replace(b'cd',b'XY') b'abXY'
bytearray是可变的二进制数据(byte)。
要构造bytearray对象,方法之一是将bytes数据做为bytearray()方法的参数,或者将str数据和编码做为参数。
例如:
>>> S = b"abcd" >>> BA = bytearray(S) >>> [ i for i in BA ] [97, 98, 99, 100] >>> BA[0] = 65 >>> BA bytearray(b'Abcd')
单字节的字符(8bit位,共256个字符,ascii只用到了7个字节)能表示出来的字符毕竟有限,例如它无法表示出中文字符。
因此,各国设计了各类多字节的字符编码来表达本身国家的文字,底层仍然使用二进制数存储,而后经过设计好的编码表将二进制数转换成各类字符。好比中国有GBK的各类编码,还有全球通用的编码类型unicode、utf-八、utf-16等。
不管什么编码,内部都包含ascii编码(也有例外,好比utf-16),它只需单个字节。也就是说,ascii编码是任何其它编码表的子集。但有些编码表强制规定每一个字符占多少个字节(好比unicode固定为2个字节),有些编码表动态决定每一个字符占多少个字节(好比utf-8是变长的,可能占用1-4个字节空间,存储字母为1个字节,存储中文字符为3个字节)。
关于unicode和utf-X格式的编码关系,粗略地能够认为utf-X是unicode格式的一种特殊类型。实际上在存储utf数据时,内部会自动在Unicode和utf之间进行转换。
要构建Unicode类型,只需加上u或U前缀。
>>> U = u"我爱你" >>> B = bytes(U,"utf-8") >>> B b'\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0' >>> BA = bytearray(U,"utf-8") >>> BA bytearray(b'\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0')
下面一张图搞懂编码、解码、编码表之间的关系。
不难看出,它们是一种根据编码表进行翻译、映射的过程:
编码:str --> bytes 解码:bytes --> str
实际上,字符串类型只有encode()方法,没有decode()方法,而bytes类型只有decode()方法而没有encode()方法。
>>> set( dir(str) ) - set( dir(bytes) ) {'encode', ... , 'isidentifier', 'format'} >>> set( dir(bytes) ) - set( dir(str) ) {'decode', 'hex', 'fromhex'}
二进制格式的数据也常称为裸数据(raw data),因此str数据通过编码后获得raw data,raw data解码后获得的str。
上面说了,编码是将字符数据转换成字节数据(raw data),解码是将字节数据转换成字符数据。在Python中字符数据也就是字符串,即str类型,字节数据也就是bytes类型或bytearray类型。
编码时,可使用字节类型的构造方法bytes()、bytearray()来构造字节,也可使用str类型的encode()方法来转换。
解码时,可使用str类型的构造方法str()来构造字符串,也可使用bytes、bytearray()类型的decode()方法。
另外须要注意的是,编码和解码的过程当中都须要指定编码表(字符集),默认采用的是utf-8字符集。
例如,使用encode()的方式将str编码为bytes数据。
>>> str1 = "abcd" >>> str2 = "我爱你" # 默认编码 >>> str1.encode() b'abcd' >>> str2.encode() b'\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0' # 显式指定使用utf-8进行编码 >>> str1.encode("utf-8") b'abcd' >>> str2.encode("utf-8") b'\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0' # 使用utf-16编码 >>> str1.encode("utf-16") b'\xff\xfea\x00b\x00c\x00d\x00' >>> str2.encode("utf-16") b'\xff\xfe\x11b1r`O' # 使用gb2312编码 >>> str1.encode("gb2312") b'abcd' >>> str2.encode("gb2312") b'\xce\xd2\xb0\xae\xc4\xe3' # 使用gbk编码 >>> str1.encode("gbk") b'abcd' >>> str2.encode("gbk") b'\xce\xd2\xb0\xae\xc4\xe3'
使用bytes()和bytearray()将str构形成bytes或bytearray数据,这两个方法都要求str->byte
的过程当中给定编码。
>>> bytes(str1,encoding="utf-8") b'abcd' >>> bytes(str1,encoding="utf-16") b'\xff\xfea\x00b\x00c\x00d\x00' >>> bytearray(str1,encoding="utf-8") bytearray(b'abcd') >>> bytearray(str2,encoding="utf-8") bytearray(b'\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0')
实际上,bytes()、bytearray()这两个方法构造字节数据的时候还有点复杂,由于能够从多个数据源来构造,好比字符串、整数值、buffer。如何使用这两个方法构造字节数据,详细内容参考help(bytes)
和help(bytearray)
给出的说明,这里给几个简单示例。
构造bytes的方式:
# 构造空bytes对象 >>> bytes() b'' # 使用str构造bytes序列,须要指定编码 >>> bytes("abcd",encoding="utf-8") b'abcd' # 使用int初始化5个字节的bytes序列 >>> bytes(5) b'\x00\x00\x00\x00\x00' # 使用可迭代的int序列构造字节序列 # int值必须为0-256之内的数 >>> bytes([65,66,67]) b'ABC' # 使用bytes或buffer来构造bytes对象 >>> bytes(b'abcd') b'abcd'
构造bytearray的方式:
# 构造空bytearray对象 >>> bytearray() bytearray(b'') # 使用bytes或buffer构造bytearray序列 >>> bytearray(b"abcd") bytearray(b'abcd') # 使用str构造bytearray序列,须要指定编码 >>> bytearray("abcd",encoding="utf-8") bytearray(b'abcd') # 使用int初始化5个字节的bytearray序列 >>> bytearray(5) bytearray(b'\x00\x00\x00\x00\x00') # 使用可迭代的int序列构造bytearray序列 # int值必须为0-256之内的数 >>> bytearray([65,66,67]) bytearray(b'ABC')
解码是字节序列到str类型的转换。
例如,使用decode()方法进行解码"我"字,它的utf-8的编码对应为"\xe6\x88\x91":
>>> b = b'\xe6\x88\x91' # 采用默认字符集utf-8 >>> b.decode() '我' # 显式指定编码表 >>> b.decode("utf-8") '我'
使用str()进行转换。
>>> str(b,"utf-8") '我'
当编码、解码的过程使用了不一样的(不兼容的)编码表时,就会出现乱码。因此,解决乱码的惟一方式是指定对应的编码表进行编码、解码。
例如,使用utf-8编码"我"字,获得一个bytes序列,而后使用gbk解码这个bytes序列。
>>> "我".encode().decode("gbk") Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'gbk' codec can't decode byte 0x91 in position 2: incomplete multibyte sequence
这里报错了,由于utf-8的字节序列里有gbk没法解码的字节。若是使用文本编辑器同样的工具去显化这个过程,获得的将是乱码字符。