Python3在处理一些底层应用时(比如socket编程)会用到字节类型(bytes)。
首先Python2与Python3的字节字符串大有不同,如果不幸看错了教程,那就悲剧了。以下内容均指Python3.
声明一个字节类型的对象
我们可以用单引号或双引号的字面量表示法得到一个字符串类型:
"Hello World"
在字符串的字面量表示前加上b字母,就可以得到一个字节类型的对象。
bt = b"Hello World"
因为我们只用了ASCII字符来创建字节类型,所以Python会自动将可读的部分按照转换为文字。如果数据是不可读的,则使用16进制来表示。
>> b"\x48" # 0x48是字母"H"对应的ASCII码
b"H"
>> b"\x01\x02\x03"
b'\x01\x02\x03'
字符串的元素是字符,bytes对象的元素则是字节,我们可以用方括号来取得每个字节。本质上,字节对象就是一个整数数组
>> bt[0]
72
得到的是一个0~255的数字(即8位二进制数字所能表示的十进制数字),我们知道,数据在计算机是用一串0和1来存储,每个0或1为一个比特(bit)又称"位",8个比特组成1个字节,即8bits=1byte。(这就是Mbps和MB/s差八倍的原因,前者是兆比特每秒,后者是兆字节每秒)
我们可以用bin(bt[0])来直观地表示每个字节在内存中的储存方式:
>> bin(bt[0])
'0b1001000'
除字面量表示之外,我们还可以用bytes()函数来得到字节类型,对于其他对象,需要实现bytes方法。
字节类型可以存储任意格式的数据,远远不限于文本,可以说图片、视频、音频等等,所以字节类型有更广阔的使用空间,是进行底层编程的不可或缺的工具。
字符串与字节类型的转换
解码与编码
字节类型转换为字符串类型的过程为解码,反之则是编码:
>> bt.decode() # 将字节类型解码为字符串类型
'Hello World'
>> s = 'Hello World' # 将字符串类型编码为字节类型
>> s.encode()
b'Hello World'
可以这样理解:数据以01的形式(机器码)存储在内存中,对人类来说是不可读的,所以要解码;反过来人类要把可读的文字存储到内存中,需要编码为计算机可以使用的数据。
decode() 和 encode()
decode() 函数有两个可选的参数: bytes.deocde(encoding="utf-8", errors="strict") ,encoding指编码,不指定则使用默认使用utf-8编码,error有三种取值:strict、ignore和replace,默认使用strict
strict 对于任何无法被解码的字符都抛出错误
ignore 忽略无法被解码的字符
replace 替换无法被解码的字符
(其它取值与codecs.register_error(name, error_handler)有关,不再讨论)
很显然后两者都不是什么好办法,最好的方法是让它抛出错误,然后再检查数据是否存在问题。
encode()与前者相反,encode()将字符串编码为字节,参数与前者相同。 因为汉字或其他语言文字需要两到三个字节来存储,字节类型的字面量表示只支持ASCII字符:
>>> b = b"你好,世界"
File "", line 1
SyntaxError: bytes can only contain ASCII literal characters.
所以我们需要encode()来获得ASCII之外的字符(比如汉字)的字节类型:
>>> s = "你好,世界"
>>> s.encode()
b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c'
str()和bytes()
使用str()和bytes()函数同样可以实现二者的转换。
首先是str(),如果直接str(b),会出现下面的情况:
>>> str(b)
"b'Hello World'" # 给出的是字面量形式
加上encoding关键字参数,让str()知道你是要解码字符串:
>>> str(b, enco