PyTips 0x08 - Python 字节与字节数组

项目地址:https://git.io/pytipshtml

0x07 中介绍了 Python 中的字符串类型,字符串类型是对人类友好的符号,但计算机只认识一种符号,那就是二进制(binary)数,或者说是数字:python

OpenCV

上面这张图片来自 OpenCV,很是直观地解释了计算机处理的信息与咱们看到的图像之间的关系。回到 Python 对字节和字节数组的定义:git

The core built-in types for manipulating binary data are bytes and bytearray.github

1Byte of ASCII

为了用计算机能够理解的数字描述人类使用的字符,咱们须要一张数字与字符对应的表。咱们都知道在计算机中 1 byte = 8bits,能够存储 0~255 共256个值,也就是说 1byte 最多能够表示 256 个字符,在最初的计算机世界中,256 足以容纳全部大小写英文字母和 0~9 阿拉伯数字以及一些经常使用的符号,因而就有了 ASCII 编码:数组

ascii

在 Python 中建立字节与字符串相似,只不过须要在引号外面加一个前缀bui

print(b"Python")
python = (b'P' b'y' b"t" b'o' b'n')
print(python)
b'Python'
b'Pyton'

Bytes 表明的是(二进制)数字的序列,只不过在是经过 ASCII 编码以后才是咱们看到的字符形式,若是咱们单独取出一个字节,它仍然是一个数字:编码

print(b"Python"[0])
80

咱们能够用 b"*" 的形式建立一个字节类型,前提条件是这里的 * 必须是 ASCII 中可用的字符,不然将会超出限制:spa

print(b"雨")
File "<ipython-input-3-1f95d71c6553>", line 1
    print(b"雨")
         ^
SyntaxError: bytes can only contain ASCII literal characters.

错误提示说明:字节类型只能容许 ASCII 字符。3d

0~127~255code

那么问题来了,咱们发现上面的 ASCII 表里面全部的字符只占据了 [31, 127],那对于这一范围以外的数字咱们要怎么才能表示为字节类型?答案就是用特殊的转义符号\x+十六进制数字 :

print(b'\xff'[0])
print(b'\x24')
255
b'$'

反过来咱们也能够将数字(0~255)转变成转义后的字节类型:

print(bytes([24]))
print(bytes([36,36,36])) # 记住字节类型是一个序列
b'\x18'
b'$$$'

或者直接从十六进制得来:

print(bytes.fromhex("7b 7d"))

# 逆运算
print(b'{ }'.hex())

int(b' '.hex(), base=16)
b'{}'
7b207d
32

encode

字符串有 decode 方法,而字节有 encode 方法,咱们这里先简单看一下 encode('ascii') 。对于给定的字符咱们能够经过编码获得它在编码表里面的坐标(即码位),所以对字符进行encode('ascii')操做是找到其在 ASCII 中的位置:

print("$".encode('ascii'))
print("$".encode('ascii')[0])
b'$'
36

也就是说字符 "$"0x07中已经介绍过这是一个 Unicode 编码的字符)在 ASCII 中的位置就是 $(或者说36)。

但是若是咱们对一些奇怪的字符进行 ASCII 编码,就会发生:

snake = '?'
try:
    snake.encode('ascii')
except UnicodeEncodeError as err:
    print(err)

# 正确的作法应该是用 UTF-8 进行编码,由于字符串都是 UTF-8 的
print(snake.encode()) # utf-8 by default
'ascii' codec can't encode character '\U0001f40d' in position 0: ordinal not in range(128)
b'\xf0\x9f\x90\x8d'

因而就获得了咱们最熟悉的错误:ordinal not in range(128),至于为何是 128,如今应该很好理解了吧!

字节数组

和字符串同样,字节类型也是不可变序列,而字节数组就是可变版本的字节,它们的关系就至关于listtuple

ba = bytearray(b'hello')
ba[0:1] = b'w'
print(ba)
bytearray(b'wello')

因为和字符串同样是序列类型,字节和字节数组可用的方法也相似,这里就不一一列举了。

总结

  1. 字节(字节数组)是二进制数据组成的序列,其中每一个元素由8bit二进制即1byte亦即2位十六进制数亦亦即0~255组成;

  2. 字节是计算机的语言,字符串是人类语言,它们之间经过编码表造成一一对应的关系;

  3. 最小的 ASCII 编码表只须要一位字节,且只占用了其中 [31,127] 的码位;

关于字节与字符串之间的关系,将在下一期[0x08]()详细介绍。

参考

  1. Pragmatic Unicode


欢迎关注公众号 PyHub!

欢迎关注公众号 PyHub!