Python学习笔记21:文本与字节序列
字符与字节
字符与字节是个编程里绕不开的话题,这东西属于那种一般平时用不到,但又不能不讲,而且还不容易理解的内容。
不过用类似的问题也很容易区分科班和非科班程序员。
话扯远了,我们回到字符和字节。从宏观上来说,字节就是机器编码,是方便于计算机存储的,而字符恰恰相反,是便于人类读写的。
最早的编码是什么我不清楚,不过ASCII应该是早期实用最广泛的编码。我现在依然能依稀回想起大学《C++大学教程》里那页ASCII编码表。
我们都知道,一个字节(byte)对应计算机里8个bit位,能表示2^8=256种可能性,对应的整数范围是0~255。
而ASCII就是用0~255编码了256种字符。
当然,这么“精简”的字符集在现代人看来会显得很不可思议,要知道现在可是个连emoji笑脸都要各种肤色都有的时代(大雾)。
所以我们发明了各种各样的编码来适应越来越多的需求,而UTF无疑是目前的佼佼者。
下面我们讨论一下Python中编码相关的各种问题。
转换
Python中字符和字节的转换很方便:
hellowStr = "Hellow world!"
hellowByte = bytes(hellowStr, encoding='ascii')
print(hellowByte)
print(hellowByte[0])
# 输出
# b'Hellow world!'
# 72
我们可以看到,字符串转换成了一个b'Hellow world'
形式的东西,这个写法正是字节序列的字面量,也就是说我们可以用这种写法直接构建字节序列。
字节序列同样可以进行切片操作,可以看到第一个元素输出是72
。
可以通过百度百科查看ASCII编码表:
可以看到72对应的正是大写字母H。
虽然我们可以实用str()
或bytes()
进行转换,但更常用的字节编码/解码方式是实用encoding
和decoding
,我们看下面的例子:
hellowBytes = "Hellow wolrd!".encode(encoding='ascii')
print(hellowBytes)
print(hellowBytes[0])
hellowStr = hellowBytes.decode(encoding='ascii')
print(hellowStr)
# b'Hellow wolrd!'
# 72
# Hellow wolrd!
这种方式显式地表明了我们正在进行ASCII编码/解码工作。
老实说,我以前也经常对编码和解码傻傻分不清,很多时候只是手熟罢了。
要是细究的话,编码就是将字符串转化为目标编码,比如ASCII就是将字符对应到0~255这256个编码上。
这个概念不仅仅存在于字节编码,比如JSON,我们将程序中的原生容器序列化为JSON格式的文本,就是进行JSON编码,从JSON文本反序列化为原生容器就是在进行JSON解码。
对于字节编码,还有一种更便于理解的方式:编码就是将人类语言转换为机器码,解码就是将机器码转换成人类能理解的字符串。
字节数组
除了字节序列,Python还提供了字节数组作为字节操作的一种容器。
hellowBytes = "你好 世界!".encode(encoding='UTF-8')
print(hellowBytes)
print(hellowBytes[0:6])
subBytes = hellowBytes[0:6]
print(subBytes.decode(encoding='UTF-8'))
hellowByteArray = bytearray(hellowBytes)
print(hellowByteArray)
print(hellowByteArray[0:6])
print(hellowByteArray[0:6].decode(encoding='UTF-8'))
# b'\xe4\xbd\xa0\xe5\xa5\xbd \xe4\xb8\x96\xe7\x95\x8c\xef\xbc\x81'
# b'\xe4\xbd\xa0\xe5\xa5\xbd'
# 你好
# bytearray(b'\xe4\xbd\xa0\xe5\xa5\xbd \xe4\xb8\x96\xe7\x95\x8c\xef\xbc\x81')
# bytearray(b'\xe4\xbd\xa0\xe5\xa5\xbd')
# 你好
这里我们实用了中文和UTF-8编码,可以更好的观察字节码和字符的区别。
可以看到,经过UTF-8编码,字节序列编程了类似\x??
这种形式,而一个\x??
正是两位16进制数。
UTF-8是一种变长编码,这说明其编码后的字节长度不确定。具体实现中会把一个字符编码为1~4个字节,其中1个字节是8位,正好可以表示为2位16进制数(2组2^4),也就是说示例中的\xe4
正好表示一个字节。事实上大多数语言编码使用3字节就够了,很少有语言会用到4字节。
我们观察可以观察到一个明显的空格,这是因为UTF-8是兼容ASCII的,而控制台可以正常地显示ASCII编码符号。空格前正好是6字节,对应你好
。
UTF-8的百科词条见这里。
此外,示例程序还展示了字节数组,其使用方式和字节序列极为相似。
内存视图
Python提供一个特殊容器memoryview
,我们可以称它为内存视图。
内存视图可以提供一种在不创建副本的情况下操作数据的能力,其实质是一种内存共享技术。
with open(file='test.png',mode='rb') as fopen:
imgView = memoryview(fopen.read(