Bytes 对象是由单个字节作为基本元素(8位,取值范围 0-255)组成的序列,为不可变对象。
Bytes 对象只负责以二进制字节序列的形式记录所需记录的对象,至于该对象到底表示什么(比如到底是什么字符)则由相应的编码格式解码所决定。我们可以通过调用 bytes() 类(没错,它是类,不是函数)生成 bytes 实例,其值形式为 b'xxxxx',其中 'xxxxx' 为一至多个转义的十六进制字符串(单个 x 的形式为:\xHH,其中 \x 为小写的十六进制转义字符,HH 为二位十六进制数)组成的序列,每两个十六进制数即每个‘x’代表一个字节(八位二进制数,取值范围 0-255),对于同一个字符串如果采用不同的编码方式生成 bytes 对象,就会形成不同的值。
Python 3最重要的新特性大概要算是对文本和二进制数据作了更为清晰的区分。文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示。Python 3不会以任意隐式的方式混用str和bytes,正是这使得两者的区分特别清晰。你不能拼接字符串和字节包,也无法在字节包里搜索字符串(反之亦然),也不能将字符串传入参数为字节包的函数(反之亦然 )。
例如:
1
2
3
4
5
6
7
|
a
=
'你好'
a_b
=
a.encode(
'utf-8'
)
print
(a_b)
for
i
in
a_b:
print
(i)
for
i
in
a_b:
print
(
bin
(i))
|
输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
b
'\xe4\xbd\xa0\xe5\xa5\xbd'
#原来如此,\xe4 长得这么丑,实际是十六进制的数字。和128,12,没什么本质的区别。自然就可以bin()变为二进制数字了。
228
189
160
229
165
189
0b11100100
0b10111101
0b10100000
0b11100101
0b10100101
0b10111101
|
这里如果直接取a_b[0],它会自动转化成十进制。但是取a_b[0:2],其类型为<class 'bytes'>
print(type(a_b[0])) 输出为<class 'int'>
print(type(a_b[0:2])) 输出为<class 'bytes'>
回到bytes
和str
的身上。bytes
是一种比特流,它的存在形式是01010001110这种。我们无论是在写代码,还是阅读文章的过程中,肯定不会有人直接阅读这种比特流,它必须有一个编码方式,使得它变成有意义的比特流,而不是一堆晦涩难懂的01组合。因为编码方式的不同,对这个比特流的解读也会不同,对实际使用造成了很大的困扰。下面让我们看看Python是如何处理这一系列编码问题的:
1
2
3
4
5
6
7
8
9
10
|
>>> s
=
"中文"
>>> s
'中文'
>>>
type
(s)
<
class
'str'
>
>>> b
=
bytes(s, encoding
=
'utf-8'
)
>>>b
b
'\xe4\xb8\xad\xe6\x96\x87'
>>>
type
(b)
<
class
'bytes'
>
|
从例子可以看出,s
是个字符串类型。Python有个内置函数bytes()
可以将字符串str
类型转换成bytes
类型,b
实际上是一串01的组合,但为了在ide环境中让我们相对直观的观察,它被表现成了b'\xe4\xb8\xad\xe6\x96\x87'
这种形式,开头的b
表示这是一个bytes
类型。\xe4
是十六进制的表示方式,它占用1个字节的长度,因此”中文“被编码成utf-8
后,我们可以数得出一共用了6个字节,每个汉字占用3个,这印证了上面的论述。在使用内置函数bytes()
的时候,必须明确encoding
的参数,不可省略。
我们都知道,字符串类str
里有一个encode()
方法,它是从字符串向比特流的编码过程。而bytes
类型恰好有个decode()
方法,它是从比特流向字符串解码的过程。除此之外,我们查看Python源码会发现bytes
和str
拥有几乎一模一样的方法列表,最大的区别就是encode
和decode
。
从实质上来说,字符串在磁盘上的保存形式也是01的组合,也需要编码解码。
如果,上面的阐述还不能让你搞清楚两者的区别,那么记住下面两几句话:
在将字符串存入磁盘和从磁盘读取字符串的过程中,Python自动地帮你完成了编码和解码的工作,你不需要关心它的过程。
使用
bytes
类型,实质上是告诉Python,不需要它帮你自动地完成编码和解码的工作,而是用户自己手动进行,并指定编码格式。Python已经严格区分了
bytes
和str
两种数据类型,你不能在需要bytes
类型参数的时候使用str
参数,反之亦然。这点在读写磁盘文件时容易碰到。