长亭百川云 - 文章详情

bytes 对象(字节串)是怎么实现的?解密它的内部原理

古明地觉的编程教室

55

2024-07-13

楔子

本篇文章来聊一聊 bytes 对象,也就是字节串,说到字节串就不得不提字符串。

  • 字符串是由任意数量的字符组成的序列,用于表示文本数据。在大多数编程语言中,字符串被视为一种高层数据类型,能够处理和操作文本信息。

  • 字节串是由任意数量的字节组成的序列,用于表示二进制数据。

字符串具有特定的字符编码,比如 UTF-8、ASCII 等等,这些编码定义了字符如何在内存中表示。而字节串没有预定义的编码,它只是原始的二进制序列,在处理非文本数据时非常有用。

计算机在存储数据以及通过网络传输数据时,数据格式都是二进制字节串,所以如果你想传输一段文本,那么必须先将它转成字节串。

word = "想说的话"  
# 字符串无法基于网络传输,它必须要转成字节串,这一过程就叫做序列化  
# 序列化时需要指定编码,比如 utf-8,utf-16,gbk 等等  
print(word.encode("utf-8"))  
"""  
b'\xe6\x83\xb3\xe8\xaf\xb4\xe7\x9a\x84\xe8\xaf\x9d'  
"""  
print(word.encode("utf-16"))  
"""  
b'\xff\xfe\xf3`\xf4\x8b\x84v\xdd\x8b'  
"""  
print(word.encode("gbk"))  
"""  
b'\xcf\xeb\xcb\xb5\xb5\xc4\xbb\xb0'  
"""

字节串传输之后还需要转成文本数据,这个过程叫做反序列化。但由于字节串不保存编码信息,它只是一坨字节流,因此反序列化时还需要知道指定的编码,如果编码指定错误,那么反序列化会失败。

# word_utf8 和 word_gbk 都只是普通的字节串  
word_utf8 = b'\xe6\x83\xb3\xe8\xaf\xb4\xe7\x9a\x84\xe8\xaf\x9d'  
word_gbk = b'\xcf\xeb\xcb\xb5\xb5\xc4\xbb\xb0'  
  
# 如果反序列化,必须要知道原始文本使用的编码是什么  
print(word_utf8.decode("utf-8"))  
print(word_gbk.decode("gbk"))  
"""  
想说的话  
想说的话  
"""  
  
# 如果指定了错误的编码,那么反序列化会失败  
try:  
    word_utf8.decode("gbk")  
except UnicodeDecodeError as e:  
    print(e)  
"""  
'gbk' codec can't decode byte 0xaf in position 4: illegal multibyte sequence  
"""

另外我们看到字符串只有 4 个字符,但序列化之后的字节串却明显多于 4 个字节。这是因为一个字节最多能表示 256 个字符,对于英文字符来说已经足够了,但对于非英文字符则力不从心,毕竟光普通的中文字符就好几千个。

所以便有了多字节编码,它使用多个字节来表示一个字符,具体使用多少个,则取决于编码。如果是 GBK 编码,那么两个字节表示一个字符,如果是 UTF-8 编码,那么三个字节表示一个字符。

所以在反序列化的时候,需要指定正确的编码,否则解析一定会失败。

以上就是关于 bytes 对象的一些基础概念,下面来看一下它的底层结构。

字节串的底层结构

字节串的类型是 bytes,那么我们有理由相信它在底层由 PyBytesObject 结构体表示。

// Include/cpython/bytesobject.h  
typedef struct {  
    PyObject_VAR_HEAD  
    Py_hash_t ob_shash;  
    char ob_sval[1];  
} PyBytesObject;

我们看一下里面的成员对象:

PyObject_VAR_HEAD:变长对象的公共头部,因为字节串是由若干个字节组成的,具有长度的概念,所以它是变长对象。

ob_shash:保存字节串的哈希值,因为计算哈希值需要遍历所有的字节,如果每获取一次哈希值都要重新计算的话,性能会有影响。所以第一次计算之后会用 ob_shash 字段保存起来,之后就不再计算了。如果 bytes 对象的哈希值尚未计算,那么 ob_shash 为 -1。

ob_sval:char 类型的数组,负责保存具体的字节。这个和整数的 ob_digit 字段的声明方式类似,由于数组长度不属于类型的一部分,因此虽然声明的时候长度是 1,但其实长度不受限制,具体是多少取决于 bytes 对象的字节数量。

我们创建几个不同的 bytes 对象,然后通过画图感受一下:

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2