struct模块使用
pyton struct模塊
struct結(jié)構(gòu)體在c語(yǔ)言中的作用,它定義了一種結(jié)構(gòu),里面包含不同類型的數(shù)據(jù)(int,char,bool等等),方便對(duì)某一結(jié)構(gòu)對(duì)象進(jìn)行處理。
在網(wǎng)絡(luò)通信當(dāng)中,大多傳遞的數(shù)據(jù)是以二進(jìn)制流(binarydata)存在的。
當(dāng)傳遞字節(jié)串時(shí),不必?fù)?dān)心太多的問(wèn)題; 傳遞字符串之前也要使用string.encode(‘utf8’)轉(zhuǎn)為字節(jié)串
而當(dāng)傳遞諸如int、char之類的基本數(shù)據(jù)的時(shí)候,就需要有一種機(jī)制將某些特定的結(jié)構(gòu)體類型打包成二進(jìn)制流的字節(jié)串然后再網(wǎng)絡(luò)傳輸,而接收端也應(yīng)該可以通過(guò)某種機(jī)制進(jìn)行解包還原出原始的結(jié)構(gòu)體數(shù)據(jù)。
python中的struct模塊就提供了這樣的機(jī)制,該模塊的主要作用就是對(duì)python基本類型值與用python字節(jié)串格式表示的C struct類型間的轉(zhuǎn)化(This module performs conversions between Python values and C structs represented as Python bytes objects.)
1. 基本的pack和unpack
原型:struct.pack(format, v1, v2, …)
struct.unpack(format, buffer)
使用pack和unpack分別對(duì)數(shù)據(jù)進(jìn)行打包和解包:
import structp_data = struct.pack('i', 25) print(p_data) print(struct.unpack('i', p_data))p1_data = struct.pack('B', 2) print(p1_data) print(struct.unpack('B', p1_data)) print(struct.calcsize('B')) # 長(zhǎng)度為一個(gè)字節(jié)# output ''' b'\x19\x00\x00\x00' (25,) b'\x02' (2,) 1 '''struct.pack.format為"i"時(shí),只能打包長(zhǎng)度為10的數(shù)字,超過(guò)10位會(huì)拋出異常:
p_data = struct.pack('i', 1234567890) print(p_data) print(struct.unpack('i', p_data)) struct.calcsize('i') # 一個(gè)'i'轉(zhuǎn)換后的長(zhǎng)度為4,2個(gè)'i'則為8# output ''' b'\xd2\x02\x96I' (1234567890,) '''轉(zhuǎn)換多個(gè)數(shù)據(jù):
data = struct.pack('hhl', 1, 2, 3) print(data) # 'hhl'分別是1,2,3的轉(zhuǎn)換格式 print(struct.unpack('hhl', data)) struct.calcsize('hhl') # 以'hhl'格式轉(zhuǎn)換得到的字節(jié)串長(zhǎng)度# output ''' b'\x01\x00\x02\x00\x03\x00\x00\x00' (1, 2, 3) '''2. format和字節(jié)順序參考表
- format格式字符前面可以有整數(shù)num, 代表有num個(gè)需要轉(zhuǎn)換的值,但’s’是例外
字節(jié)順序的大端模式和小端模式
print(struct.pack('>i', 0x12345678)) # 大端模式, 地址從低到高,數(shù)據(jù)位從高到低 print(struct.pack('<i', 0x12345678)) # 小端模式3. 使用struct的原因
將int轉(zhuǎn)為bytes方法的速度比較:
import timeit print(timeit.timeit('bytes([255])', number=1000000)) print(timeit.timeit('struct.pack("B", 255)', setup='import struct', number=1000000)) print(timeit.timeit('(255).to_bytes(1, byteorder="little")', number=1000000))output
0.1463956000006874 0.08819799999764655 0.1185951000006753結(jié)論: struct.pack() 函數(shù)執(zhí)行整型到字節(jié)的轉(zhuǎn)換可獲得最佳執(zhí)行性能
4. 利用buffer,使用pack_into和unpack_from方法
使用二進(jìn)制打包數(shù)據(jù)的場(chǎng)景大部分都是對(duì)性能要求比較高的使用環(huán)境。
而在上面提到的pack方法都是對(duì)輸入數(shù)據(jù)進(jìn)行操作后重新創(chuàng)建了一個(gè)內(nèi)存空間用于返回,也就是說(shuō)我們每次pack都會(huì)在內(nèi)存中分配出相應(yīng)的內(nèi)存資源,這有時(shí)是一種很大的性能浪費(fèi)。
struct模塊還提供了pack_into() 和 unpack_from()的方法用來(lái)解決這樣的問(wèn)題,也就是對(duì)一個(gè)已經(jīng)提前分配好的buffer進(jìn)行字節(jié)的填充,而不會(huì)每次都產(chǎn)生一個(gè)新對(duì)象對(duì)字節(jié)進(jìn)行存儲(chǔ)。
data = (b'ccc', 25, 38) buf = bytearray(struct.calcsize('3s2i')) # 預(yù)先創(chuàng)建一個(gè)緩沖區(qū)buf struct.pack_into('3s2i', buf, 0, *data) # 將打包的字節(jié)填充到緩沖區(qū),從下標(biāo)為0的位置開(kāi)始 struct.unpack_from('3s2i', buf, 0) # 從緩沖區(qū)buf下標(biāo)為0的位置讀取數(shù)據(jù),并按格式'3s2i'解包相比使用pack方法打包,pack_into 方法一直是在對(duì)buffer對(duì)象進(jìn)行操作,而不會(huì)像pack那樣要每次創(chuàng)建內(nèi)存用于緩存字節(jié)串。
使用pack_into的offset參數(shù),可以將多個(gè)python對(duì)象pack到一個(gè)緩沖區(qū)對(duì)象中,并可利用offset進(jìn)行unpack:
data = (b'ccc', 25, 38) data_format = '3s2i'data2 = (b'cze', 10) data2_format = '3si' buf = bytearray(struct.calcsize(data_format) + struct.calcsize(data2_format)) struct.pack_into(data_format, buf, 0, *data) struct.pack_into(data2_format, buf, struct.calcsize(data_format), *data2)print(struct.unpack_from(data_format, buf, 0)) print(struct.unpack_from(data2_format, buf, struct.calcsize(data_format)))# output ''' (b'ccc', 25, 38) (b'cze', 10) '''5. 使用struct.Struct類簡(jiǎn)化操作
上面使用原始的函數(shù)將多個(gè)python對(duì)象pack到一個(gè)緩沖區(qū)隊(duì)中的代碼有些啰嗦,使用struct.Struct類創(chuàng)建一個(gè)Struct對(duì)象并調(diào)用其方法比使用相同格式的struct函數(shù)更有效,因?yàn)楦袷阶址恍枰幾g一次
import structdata = (b'ccc', 25, 38) data2 = (b'cze', 10)s1_obj = struct.Struct('3s2i') s2_obj = struct.Struct('3si')buf = bytearray(s1_obj.size + s2_obj.size)s1_obj.pack_into(buf, 0, *data) s2_obj.pack_into(buf, s1_obj.size, *data2)print(s1_obj.unpack_from(buf, 0)) print(s2_obj.unpack_from(buf, s1_obj.size))# output ''' (b'ccc', 25, 38) (b'cze', 10) '''參考
淺析Python中的struct模塊
總結(jié)
以上是生活随笔為你收集整理的struct模块使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 多台计算机共享内存_共享内存多处理器和指
- 下一篇: Python 爬虫 | 爬取股票概念数据