bytesbytearray 是python非常重要的数据类型,但其重要性经常被我们忽视了。在实际开发过程中,又总是遇到 bytes 类型。举例,pickle 序列化, json序列化就是将对象转为bytes类型。字符串编码问题也是1个常见的bytes相关问题,图像数据都是bytes类型,等等。
另外,bytes, bytearray 直接处理二进制数据, 处理速度比str, list, tuple等类型要快很多,适合性能要求高的应用开发,如图像处理,网络通信等。memoryview提供了1种以数组方式访问内存数据的方式,进一步方便了bytes类型的使用。

本文将介绍bytes类型数据的创建及各类操作,与其它类型之间的转换,字符串编码解码原理,bytearraymemoryview 的基本语法以及常见使用方式。

1、生成bytes变量的方法:

可以多种方法生成bytes变量实例,如下面的例子

>>> bytes(b'hello world')  # 使用字节串实例创建
b'hello world'
bytes(10)   # 指定生成10个全零的字节串, 字节串空值就是0.
>>> bytes(10)
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
bytes(range(20))   # 生成1个序列
>>> bytes(range(20))
b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13'
bytes(binary_obj) # 如果是字符串对象,需要 encoding参数

Bytes与各种数据类型之间的转换

字符串转bytes

字符串转bytes, 是用 encode() 方法
data = str_data.encode(encoding="utf-8")

>>> str = "你好,世界"
>>> byte_data = str.encode(encoding='utf-8')
>>> byte_data
b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c'

bytes 类型字符串在屏幕显示时,除了ascii字符外,其它字符无法以可读方式显示。

bytes 转字符串:

byte_data.decode(encoding="utf-8")

int 转 bytes

用int对象的to_bytes()方法

# int variable
num = 7
# int to bytes
num_bytes = num.to_bytes(2, byteorder='big')
# display result and type
print(num_bytes)
print(type(num_bytes))

第2个参数,表示双字节整数中高低字符顺序,big 表示正常顺序,即低字节在前,高字节在后。 本例输出:

b'\x00\x07'
<class 'bytes'>

little 表示,高字节在前,低字节在后。上例中,将2个参数改为little, 则显示出的数字为b’\x07\x00’

>>> num = 7
>>> num_bytes = num.to_bytes(2, byteorder='little')
>>> print(num_bytes)
b'\x07\x00'
>>> print(type(num_bytes))
<class 'bytes'>

bytes 转int , 使用 int.from_bytes()方法

>>> d=3324
>>> byte_data=d.to_bytes(5,"big")
>>> byte_data
b'\x00\x00\x00\x0c\xfc'
>>> int_data = int.from_bytes(byte_data,"big")
>>> int_data
3324

float类型无法直接转换为bytes, 可以先转为string, 再转为bytes.

dict, tuple, list 转bytes

dict, list, tuple 转bytes, 通常使用pickle序列化, 或用 json序列化
pickle 序列化就是将对象转为字节码,保存进文件,或者 bytes变量。
json也是字节串,只是各种软件都支持json格式识别,所以可以方便显示查看。

>>> import pickle
>>> dl
[30, 203, 3, 133333383]
>>> by10 = pickle.dumps(dl)
>>> type(by10)
<class 'bytes'>
>>> pickle.loads(by10)
[30, 203, 3, 133333383]
>>>

上面的例子可以看到,当用pick.dump(dl)序列化后,by10是1个bytes类型。

bytes 变量内容的操作

基本上字符串支持的操作,bytes 字节串也都支持,只不过是二进制方式,可读性较差。 .
如在字符串中查找、替换字符等

>>> a=b"alibaba"
>>> a.count(b'a')
3
>>> a.find(b'a',3)
4
>>> chr(a[4])
'a'
>>> b=a.replace(b'a',b'x')
>>> b
b'xlibxbx'

注意 bytes 类型是 immutable, 其值不可修改。

2、字符串编码与解码

字符串的编码与解码,其实就是将指定协议,字符串转换为bytes类型,以及从bytes类型转回字符串的过程。

字符编码协议

在计算机低层是用二进制码来运行的,只有0和1。计算机基本存储单位为字节, 8 比特(bit)等于1个字节(byte),即一个字节能表示的最大整数是 255(1111 1111)。最初的字符集格式为用1个字节来表示所有字符,也就是 ASCII 字符集,可以表示 256 个字符,支持英文字母,数字和少部分符号。
用1个字节用来表示1万个汉字显然不够,日文也存在同样问题。 为了统一编码方式来表示世界各国语言文字,出现了Unicode 字符集,它通常采用2个字节来表示1个字符。但有的字符多于2个字节。但对于法文等小字符集语言来说浪费了太多的比特位,因此在Unicode基础上又发展出可变长的UTF-8 编码方式,这也是python3默认的编码方式。

什么时候需要对字符串进行编码、解码?

字符串是可读方式的数据。但字符串内容在内存中也是以二进制方式存储。可以认为,字符串在内存中的形式是指定编码格式的1块内存数据。例如 "Python字符“这几个字符,5个英文字符 + 2个汉字,默认utf-8编码格式。Python UTF-8 编码,1个英文字母为1个字节,1个常用汉字是3个字节。
程序从字符串数据区读取数据的方式:

  • 第1-6字节,单字节转换为英文显示
  • 第7到12个字节,每3个字节为1个汉字编码,
>>> len(bytes('Python字符','utf-8'))
12
>>>

由于 string 类还封装了许多其它方法与属性,以及与系统的交互,最终实现汉字在屏幕上显示出来,所以包含Python字符 的string对象在内存中的占据字节数远不止12个字节。但转换成bytes后只有12个字节,保存在文件中,在网络发送时,非常节省资源,

需要显式地对字符串进行编码的场景主要有

  • 网络通信的发送侧, socket传输数据需要按字节传送,以占用更少网络资源, 因此通常需要将字符串提前转为字节码,也就是告知socket,,这块数据是用utf-8编码的,方式就是 data = strdata.encode( encoding="utf-8"), 这时data 的类型是 bytes
  • 在网络接收侧,收到数据,或者从文件中得到1块数据,且知道编码格式,用decode() 方法将字节数据转为字符串。
  • 用序列化方式保存文件,先将字符串转换为二进制编码,必须要指定编码格式,转换为二进制后保存,可以节省一些空间,同时提高了保密性。
  • 使用 ctyps 进行 c/c++函数参数转换时,c++字符串,指针等类型,对应的都是python的bytes类型。

Python 编码和解码函数

encod()decode() 分别对应编码和解码函数,

编码:就是把可读的字符串,按指定编码格式,将字符逐一转换为二进制码,没有其它多余的数据。中文转换后,屏幕上显示为16进制数,只有ascii字符会显示,但在前面加个b’ ’ ,表示这是字节串。

my_b = '技能树'.encode('utf-8')
print('编码后',my_b) # 编码后 b'\xe6\x8a\x80\xe8\x83\xbd\xe6\xa0\x91'>>> my_b = "hello world".encode('utf-8')
>>> my_b
b'hello world'

解码操作,就是把 bytes型数据转换为可读形式的数据类型,如下所示:

my_b = '技能树'.encode('utf-8')
print('编码后', my_b)  # 编码后 b'\xe6\x8a\x80\xe8\x83\xbd\xe6\xa0\x91'my_str = my_b.decode('utf-8')
print("解码后", my_str)

解码后出现乱码,通常是解码指定的编码格式与编码时的不一致。 而且这种问题通常发生在网络接口上。 最常见问题:
HTTP GET请求有中文参数时,常遇到编解码问题
主要原因:http协议对URL参数的编码要求是ASCII字符集,汉字是UTF-8。在发送时要进行两次编码才能将汉字转为ASCII字节码:

  • 第1次编码, 用 UTF-8 字符集,每个字符占3个字节。
  • 第2次编码,可以用 iso-8859-1,也可以用其它字符集,转为ASCII。

接收方也要进行两次解码,才能正确地还原汉字。

还好python 内置库urllib 提供了1条命令,1次就可以将汉字转为ASCII编码。
编码: urllib.parse.urlencode(dic)
解码: urllib.parse.unquote(dic or str)
示例代码

keyword = "天气预报"
param_list = urllib.parse.urlencode( { 'q' : keyword } )
header = {'user-Agent':’haha‘}
url = 'http://www.baidu.com/s/'
response = request.get( url, params=param_list, headers = header )

字符编码值查看与转换

通过 ord() 函数获取字符的整数表示,通过 chr() 将整数转换为字符,例如下述代码

print(ord('爬')) # 29228
print(chr(29228))

3、Bytearray的使用

3.1 bytearray 类型的主要使用场景

bytearray 字节数组,使用方法与bytes类似,使用bytearray的主要原因:

  • 对bytes类型的数据进行增删改场景,如需要修改二进制文件,图片,音频文件等。
  • bytearray是 mutable,即可以修改元素值。也支持切片索引。sring类型是immutable,所以bytearray适用于对字符串进行增删改时。
  • 调用 C/C++ 函数时,用于获取二进制数据类型指针变量内容

3.2 bytearray 基础用法

创建bytearray变量语法:
variable_name = bytearray(source, encoding, errors),

每个元素为1个字符,如果不指定encoding, 默认是ascii,

>>> str = "Geeksforgeeks"
>>> array1 = bytearray(str, 'utf-8')
>>> print(array1)
bytearray(b'Geeksforgeeks')
>>> array1[3]
107
>>> chr(array1[3])
'k'
>>> len(array1)
13
>>> len(str)
13
>>>

中文字符转 bytearray

>>> str = "你好,世界"
>>> array2 = bytearray(str, 'utf-16')
>>> array2
bytearray(b'\xff\xfe`O}Y\x0c\xff\x16NLu')
>>>

int 转bytearray 类型
int型数据应放入1个数组,每个数据不大于255,否则报错


>>> dl = [ 30, 203, 3, 183]
>>> array3 = bytearray(dl)
>>> print(array3)
bytearray(b'\x1e\xcb\x03\xb7')
>>> len(array3)
4>>> dl = [ 30, 203, 3, 133333383]
>>> array3 = bytearray(dl)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
ValueError: byte must be in range(0, 256)

3.3 对字符串进行操作

在bytearray二进制字符串中查找字符
命令格式 bytearray.find(sub[, start[, end]])

>>> arr1 = bytearray(b"aaaahellocccc")
>>> arr1.find(b'h',0,)
4
>>>

string类型无法直接修改字符串,转为bytearray类型后可以进行修改。

>>> str1 = "Geeksforgeeks"
>>> array1 = bytearray(str1.encode())
>>> array1
bytearray(b'Geeksforgeeks')
>>> array1.replace(b's',b'x')
bytearray(b'Geekxforgeekx')

3.4 获取ctypes 指针变量内容

此示例,用ctypes 生成1个 c_ubyte类型数组,使用ctypes.memmove() 将该数组内容复制到barray变量,注意这是内存深拷贝方式。

data = (ctypes.c_ubyte *5)(0x11,0x22,0x33,0x44,0x55)
barray = bytearray(5)
ptr1 = (ctypes.c_ubyte * 5).from_buffer(barray)
ctypes.memmove(ptr1,data, 5)
print(f" barray[4] {barray[4]:#X}")

输出:

barray[4] 0X55

4. 内存视图 Memoryview

memoryview 对象允许 Python 代码访问一个对象的内部数据,只要该对象支持缓冲区协议而无需进行拷贝. 当前支持缓冲区协议的对象主要有bytes, bytearray, array.array数组。
可以理解为:memoryview 可用数组的方式来访问关联对象的数据,支持切片索引等数组的通用操作。从这点来看,memoryview 类似于C语言的指针功能。

示例,用 memoryview 来访问 bytes对象

>>> v = memoryview(b'abcefg')
>>> v[1]
98
>>>v[-1]
103
>>>v[1:4]
<memory at 0x7f3ddc9f4350>
>>>bytes(v[1:4])
b'bce

下层对象使用array的示例, 用数组方式访问成员,用tolist()方法可将数组转为list 类型

>>>import array
>>>a = array.array('l', [-11111111, 22222222, -33333333, 44444444])
>>>m = memoryview(a)
>>>m[0]
-11111111
>>>m[-1]
44444444
>>>m[::2].tolist()
[-11111111, -33333333]

如果下层对象是mutable, 也可以通过memory view来赋值

data = bytearray(b'abcefg')
v = memoryview(data)
v.readonly
False
v[0] = ord(b'z')
data
bytearray(b'zbcefg')

主要属性:

  • obj 内存视图的下层对象
  • readonly true/false
  • itemsize 每个元素的大小, 对于bytes, bytearray,此值为1
  • ndim 表示内存所代表的多维数组具有多少个维度
  • shape 表示 memoryview数组的维度
  • strides 一个整数元组,通过 ndim 的长度给出以字节表示的大小,以便访问数组中每个维度上的每个元素

主要方法

  • tolist(), 导出为list
a = array.array('I', [1, 2, 3, 4, 5])
x = memoryview(a)
x.tolist()
  • tobytes() 将缓冲区中的数据作为字节串返回。 这相当于在内存视图上调用 bytes 构造器。
  • hex() 用16进制表示缓冲区中的字节
  • release() 释放对象

Python 数据类型 bytes 与 bytearray 使用教程相关推荐

  1. python bytearray拼接_python数据类型 ——bytes 和 bytearray

    bytes和 bytearray bytes:可以看作是一组二进制数值(0-255) 的 str 序列 bytearray:可以看作是一组二进制数值(0-255) 的 list 序列 bytes类型 ...

  2. Python:bytes、bytearray

    bytes.bytearray Python3引入两个新类型 bytes:不可变字节序列 bytearray:字节数组.可变 字符串与bytes 字符串是字符组成的有序序列,字符可以使用编码来理解 b ...

  3. Python 数据类型--Bytes类型

    一.Bytes类型 在Python3以后,字符串和bytes类型彻底分开了.字符串是以字符为单位进行处理的,bytes类型是以字节为单位处理的. bytes数据类型在所有的操作和使用甚至内置方法上和字 ...

  4. Python str / bytes / unicode 区别详解 - Python零基础入门教程

    目录 一.前言 二.Python str / bytes / unicode 区别 1.Python2.x 版本中 str / bytes / unicode 区别 2.Python3.x 版本中 s ...

  5. python中byte2array报错_python基础-bytes和bytearray的用法

    Python中的序列类型有bytes和bytearray. 二进制序列类型的用法比较少见,是python中少用的一种序列类型,对于二进制序列类型,大家基本了解即可. bytes二进制序列类型 指定长度 ...

  6. Python基础数据类型---bytes

    由于Python的字符串类型是str,在内存中以Unicode表示,一个字符对应若干个字节.如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes. Python对bytes ...

  7. python中byte类型_详解python string类型 bytes类型 bytearray类型

    搜索热词 一.python3对文本和二进制数据做了区分.文本是Unicode编码,str类型,用于显示.二进制类型是bytes类型,用于存储和传输.bytes是byte的序列,而str是unicode ...

  8. Python 之 bytes/bytearray 的深入浅出

    Python 之 bytes/bytearray 的深入浅出 1.前言 1.1 Python3 引入两个新类型 1.2 ASCII 1.3 字符串与`bytes bytearray` 1.4 编码与解 ...

  9. Python: bytes、bytearray 详解

    文章目录 写在开头的话 Python: bytes.bytearray 00. 概述 01.bytes定义 02. bytes操作 03. bytearray定义 04. bytearray操作 05 ...

最新文章

  1. 微信小程序wx.navigateTo路由循环嵌套问题解决
  2. Python3.5+selenium操作Chrome浏览器的简单实例
  3. Linux上搭建Hadoop2.6.3集群以及WIN7通过Eclipse开发MapReduce的demo
  4. Angular+Flask搭建一个记录工具
  5. 51Nod - 2142身份证号排序
  6. ElasticSearch搜索实例含高亮显示及搜索的特殊字符过滤
  7. opencv 学习笔记6:通道的拆分与合并
  8. 响应式html5模板代码,响应式多用途HTML5模板
  9. java restful接口测试_详解SpringBoot restful api的单元测试
  10. java打印日期序列,Java GSON-日期格式
  11. Java web后台插入数据库中文乱码问题解决
  12. js中的substr和substring
  13. 使用接口根据关键词取亚马逊商品数据
  14. 安立公司推出CPRI RF 测量选件
  15. 台式计算机机箱型号及价格,顶级组装台式电脑配置清单
  16. VMware虚拟机里如何改硬盘型号躲避防封检测
  17. Android课设之校园二手交易app
  18. 洛谷—P3387 【模板】缩点
  19. Harmonious Army
  20. 【Linux】数字ICer需要用到哪些Linux命令?

热门文章

  1. VBA RemoveDuplicates方法去重复项
  2. 22考研上交电通819初试394分一战上岸记录
  3. MQTT设备模拟器(全部代码)
  4. Pr:同步音频和视频
  5. DB2 更新记录update时碰到sqlcode = 911锁表的问题
  6. 辉仔日记之学代码第八期——葫芦娃原来是多态!
  7. HDU 5721 Palace(平面最近点对(分治))
  8. qHD、HD、FHD、QHD、UHD的区别
  9. 远程登录Linux(window下操作Linux)
  10. oracle root密码重置,Exadata存储节点root用户密码重置