定义
- string是文本序列
- bytes是字节序列
区别
- 文本是有编码的,例如:utf8,gbk,GB18030等
- 字节没有编码
- 文本的编码指的是字符如何使用字节来表示
编码
- 单字节编码,例如:ascii
- 多字节编码,例如:utf8
编码是信息从一种形式或格式转换为另一种形式的过程,也称为计算机编码语言的代码,简称编码。python3中,字符串默认使用utf8编码。
bytes:字符串经过编码后的数据类型。
用utf8编码表示的字节如下:
>>> s = '人人都会有迷茫不知所措的时候'
>>> type(s)
<class 'str'>
>>> s.encode()
b'\xe4\xba\xba\xe4\xba\xba\xe9\x83\xbd\xe4\xbc\x9a\xe6\x9c\x89\xe8\xbf\xb7\xe8\x8c\xab\xe4\xb8\x8d\xe7\x9f\xa5\xe6\x89\x80\xe6\x8e\xaa\xe7\x9a\x84\xe6\x97\xb6\xe5\x80\x
99'
每个字符有3个字节(3个16进制数组成)
‘人’的utf8字节为:b'\xe4\xba\xba
再来看下十六进制数转换成十进制数的例子:
>>> 0x23
35
>>> 0xe4
228
>>> 0x3a
58
#转成二进制
>>> bin(0x23)
'0b100011'
>>> bin(0xe4)
'0b11100100'
#0b代表这个数是二进制
我们也可以encode其它字节:
>>> s = '人人都会有迷茫不知所措的时候'
>>> s.encode('gbk')
b'\xc8\xcb\xc8\xcb\xb6\xbc\xbb\xe1\xd3\xd0\xc3\xd4\xc3\xa3\xb2\xbb\xd6\xaa\xcb\xf9\xb4\xeb\xb5\xc4\xca\xb1\xba\xf2'
#gbk编码出来的与utf8出来的字节不一样
#计算机中均是如此表示的,不单单是python如此
bytes是可以转换成字符串的
>>> b = s.encode('gbk')
>>> b.decode('gbk')
'人人都会有迷茫不知所措的时候'
>>> b = s.encode()
>>> b.decode()
'人人都会有迷茫不知所措的时候'
事实上,转换可能会出现乱码,而乱码是没法转化的。
gbk是双字节,而utf8是三字节,所以会产生不对应。通常来说,绝大部分中文都是utf8三字节。unicode都是固定字节编码的,UTF-8用1到4个字节编码Unicode字符。
为什么要用编码?
因为我们现在的应用都是跨网络的。比如:
- 服务器是linux utf8
- 客户端时windows gbk
- 通过socket通信
当客户端发送了一个gbk字符串给linux服务器,linux就需要转码,否则就会乱掉。客户端默认为gbk,服务端用decode utf8就会失败,故需要做约定,gbk为gbk,然后用decode gbk解码,不能突然变成utf8。
因此在python3中,socket只能用bytes
(python2是不区分bytes和string的。)
bytes
-
bytes的定义
string的所有操作,bytes都支持bytes由str通过encode方法转化得到 通过b前缀定义bytes
b前缀如下:
>>> bt = b'\xe4\xba\xba'
>>> type(bt)
<class 'bytes'>
>>> bt2 = b'abc'
>>> type(bt2)
<class 'bytes'>
- bytes的操作
bytes的方法里绝大多数都是string的方法
bytes的操作除了encode外,str操作都有对于bytes的版本,但是传入参数也必须是bytes,如果传入字符串会报错。
bytes的操作是按字节来的:
>>> s = '人人都会有迷茫不知所措的时候'
>>> s.encode()
b'\xe4\xba\xba\xe4\xba\xba\xe9\x83\xbd\xe4\xbc\x9a\xe6\x9c\x89\xe8\xbf\xb7\xe8\x8c\xab\xe4\xb8\x8d\xe7\x9f\xa5\xe6\x89\x80\xe6\x8e\xaa\xe7\x9a\x84\xe6\x97\xb6\xe5\x80\x
99'
>>> s.encode().find(b'\xe4')
0
#长度也是按照字节来计算的:
>>> len(s.encode())
42
#bytes.decode()转化为str,bytes.hex()转化为16进制:
>>> bt = b'\xe4\xba\xba'
>>> bt.decode()
'人'
>>> bt.hex()
'e4baba'
bytearray
- bytearray的定义
bytearray是bytes的可变版本,str和bytes是不可变的
>>> bt = '人人都会有迷茫不知所措的时候'.encode()
>>> bt[0]
228
>>> bt2 = b'abc'
>>> bt2[1]
98
#将bytes转化为bytearray:
>>> ba = bytearray(bt)
>>> ba
bytearray(b'\xe4\xba\xba\xe4\xba\xba\xe9\x83\xbd\xe4\xbc\x9a\xe6\x9c\x89\xe8\xbf\xb7\xe8\x8c\xab\xe4\xb8\x8d\xe7\x9f\xa5\xe6\x89\x80\xe6\x8e\xaa\xe7\x9a\x84\xe6\x97\xb6
\xe5\x80\x99')
>>> type(ba)
<class 'bytearray'>
- bytes不可变&bytearray可变
bytes的时候是不可以赋值的:
>>> bt[0] = b'a'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'bytes' object does not support item assignment
但是bytearray是可变类型:
>>> ba = bytearray(b'abc')
>>> ba[0] = int(b'D'.hex(),16)
>>> ba
bytearray(b'Dbc')
- bytearray更新的时候,也是一个一个字节更新的,不是一个字符串
- 要把字节转换成十六进制数进行更替
-
使用场景
有一种数据处理叫:图像处理
当需要修改图片时,图片保存成了字节,bytes不可变,当一个图片修改一处就是3M,修改100处就是300M,对于图片的像素级修改,内存占用量如此高时不可行的,故而需要一个可变版本的bytes。 -
bytearray的方法
相对bytes来说,多了insert,append,extend,pop,remove,clear,reserver。其实就是多出了list的那些方法,并且可以索引操作。
但和修改bytearray一样,所有的方法中,都需要用int来表示,而非bytes本身:
>>> ba.insert(int(b'E'.hex(),16),0)
>>> ba
bytearray(b'Dbc\x00')
>>> ba.append(20)
>>> ba
bytearray(b'Dbc\x00\x14')
int必须在0~256这个范围内,即8为的无符号整数
小结
学习了字符串和bytes,以及bytes的可变类型bytearray。
在经过前面的学习之后发现后面的也会比较能理解,果然学习都是一步一步的脚印额。虽然还是或多或少不熟悉的地方,再经过几遍练习就好了吧!