Python標(biāo)準(zhǔn)庫筆記struct模塊的使用
最近在學(xué)習(xí)python網(wǎng)絡(luò)編程這一塊,在寫簡(jiǎn)單的socket通信代碼時(shí),遇到了struct這個(gè)模塊的使用,當(dāng)時(shí)不太清楚這到底有和作用,后來查閱了相關(guān)資料大概了解了,在這里做一下簡(jiǎn)單的總結(jié)。
了解c語言的人,一定會(huì)知道struct結(jié)構(gòu)體在c語言中的作用,它定義了一種結(jié)構(gòu),里面包含不同類型的數(shù)據(jù)(int,char,bool等等),方便對(duì)某一結(jié)構(gòu)對(duì)象進(jìn)行處理。而在網(wǎng)絡(luò)通信當(dāng)中,大多傳遞的數(shù)據(jù)是以二進(jìn)制流(binary data)存在的。當(dāng)傳遞字符串時(shí),不必?fù)?dān)心太多的問題,而當(dāng)傳遞諸如int、char之類的基本數(shù)據(jù)的時(shí)候,就需要有一種機(jī)制將某些特定的結(jié)構(gòu)體類型打包成二進(jìn)制流的字符串然后再網(wǎng)絡(luò)傳輸,而接收端也應(yīng)該可以通過某種機(jī)制進(jìn)行解包還原出原始的結(jié)構(gòu)體數(shù)據(jù)。python中的struct模塊就提供了這樣的機(jī)制,該模塊的主要作用就是對(duì)python基本類型值與用python字符串格式表示的C struct類型間的轉(zhuǎn)化(This module performs conversions between Python values and C structs represented as Python strings.)。stuct模塊提供了很簡(jiǎn)單的幾個(gè)函數(shù),下面寫幾個(gè)例子。
該模塊作用是完成Python數(shù)值和C語言結(jié)構(gòu)體的Python字符串形式間的轉(zhuǎn)換。這可以用于處理存儲(chǔ)在文件中或從網(wǎng)絡(luò)連接中存儲(chǔ)的二進(jìn)制數(shù)據(jù),以及其他數(shù)據(jù)源。
用途: 在Python基本數(shù)據(jù)類型和二進(jìn)制數(shù)據(jù)之間進(jìn)行轉(zhuǎn)換
struct模塊提供了用于在字節(jié)字符串和Python原生數(shù)據(jù)類型之間轉(zhuǎn)換函數(shù),比如數(shù)字和字符串。
模塊函數(shù)和Struct類
它除了提供一個(gè)Struct類之外,還有許多模塊級(jí)的函數(shù)用于處理結(jié)構(gòu)化的值。這里有個(gè)格式符(Format specifiers)的概念,是指從字符串格式轉(zhuǎn)換為已編譯的表示形式,類似于正則表達(dá)式的處理方式。通常實(shí)例化Struct類,調(diào)用類方法來完成轉(zhuǎn)換,比直接調(diào)用模塊函數(shù)有效的多。下面的例子都是使用Struct類。
Packing(打包)和Unpacking(解包)
Struct支持將數(shù)據(jù)packing(打包)成字符串,并能從字符串中逆向unpacking(解壓)出數(shù)據(jù)。
在本例中,格式指定器(specifier)需要一個(gè)整型或長(zhǎng)整型,一個(gè)兩個(gè)字節(jié)的string,和一個(gè)浮點(diǎn)數(shù)。格式符中的空格用于分隔各個(gè)指示器(indicators),在編譯格式時(shí)會(huì)被忽略。
import struct import binascii values = (1, 'ab'.encode('utf-8'), 2.7) s = struct.Struct('I 2s f') packed_data = s.pack(*values) print('原始值:', values) print('格式符:', s.format) print('占用字節(jié):', s.size) print('打包結(jié)果:', binascii.hexlify(packed_data))
# output
原始值: (1, b'ab', 2.7)
格式符: b'I 2s f'
占用字節(jié): 12
打包結(jié)果: b'0100000061620000cdcc2c40'
這個(gè)示例將打包的值轉(zhuǎn)換為十六進(jìn)制字節(jié)序列,用binascii.hexlify()方法打印出來。
使用unpack()方法解包。
import struct import binascii packed_data = binascii.unhexlify(b'0100000061620000cdcc2c40') s = struct.Struct('I 2s f') unpacked_data = s.unpack(packed_data) print('解包結(jié)果:', unpacked_data)
# output
解包結(jié)果: (1, b'ab', 2.700000047683716)
將打包的值傳給unpack(),基本上返回相同的值(浮點(diǎn)數(shù)會(huì)有差異)。
字節(jié)順序/大小/對(duì)齊
默認(rèn)情況下,pack是使用本地C庫的字節(jié)順序來編碼的。格式化字符串的第一個(gè)字符可以用來表示填充數(shù)據(jù)的字節(jié)順序、大小和對(duì)齊方式,如下表所描述的:
Character | Byte order | Size | Alignment |
---|---|---|---|
@ | 本地 | 本地 | 本地 |
= | 本地 | standard | none |
< | little-endian(小字節(jié)序) | standard | none |
> | big-endian(大字節(jié)序) | standard | none |
! | network (= big-endian) | standard | none |
如果格式符中沒有設(shè)置這些,那么默認(rèn)將使用 @。
本地字節(jié)順序是指字節(jié)順序是由當(dāng)前主機(jī)系統(tǒng)決定。比如:Intel x86和AMD64(x86-64)使用小字節(jié)序; Motorola 68000和 PowerPC G5使用大字節(jié)序。ARM和Intel安騰支持切換字節(jié)序??梢允褂胹ys.byteorder查看當(dāng)前系統(tǒng)的字節(jié)順序。
本地大小(Size)和對(duì)齊(Alignment)是由c編譯器的sizeof表達(dá)式確定的。它與本地字節(jié)順序?qū)?yīng)。
標(biāo)準(zhǔn)大小由格式符確定,下面會(huì)講各個(gè)格式的標(biāo)準(zhǔn)大小。
示例:
import struct import binascii values = (1, 'ab'.encode('utf-8'), 2.7) print('原始值 : ', values) endianness = [ ('@', 'native, native'), ('=', 'native, standard'), ('<', 'little-endian'), ('>', 'big-endian'), ('!', 'network'), ] for code, name in endianness: s = struct.Struct(code + ' I 2s f') packed_data = s.pack(*values) print() print('格式符 : ', s.format, 'for', name) print('占用字節(jié): ', s.size) print('打包結(jié)果: ', binascii.hexlify(packed_data)) print('解包結(jié)果: ', s.unpack(packed_data))
# output
原始值 : (1, b'ab', 2.7)格式符 : b'@ I 2s f' for native, native
占用字節(jié): 12
打包結(jié)果: b'0100000061620000cdcc2c40'
解包結(jié)果: (1, b'ab', 2.700000047683716)格式符 : b'= I 2s f' for native, standard
占用字節(jié): 10
打包結(jié)果: b'010000006162cdcc2c40'
解包結(jié)果: (1, b'ab', 2.700000047683716)格式符 : b'< I 2s f' for little-endian
占用字節(jié): 10
打包結(jié)果: b'010000006162cdcc2c40'
解包結(jié)果: (1, b'ab', 2.700000047683716)格式符 : b'> I 2s f' for big-endian
占用字節(jié): 10
打包結(jié)果: b'000000016162402ccccd'
解包結(jié)果: (1, b'ab', 2.700000047683716)格式符 : b'! I 2s f' for network
占用字節(jié): 10
打包結(jié)果: b'000000016162402ccccd'
解包結(jié)果: (1, b'ab', 2.700000047683716)
格式符
格式符對(duì)照表如下:
Format | C Type | Python type | Standard size | Notes |
---|---|---|---|---|
x | pad byte | no value | ||
c | char | bytes of length 1 | 1 | |
b | signed char | integer | 1 | (1),(3) |
B | unsigned char | integer | 1 | (3) |
? | _Bool | bool | 1 | (1) |
h | short | integer | 2 | (3) |
H | unsigned short | integer | 2 | (3) |
i | int | integer | 4 | (3) |
I | unsigned int | integer | 4 | (3) |
l | long | integer | 4 | (3) |
L | unsigned long | integer | 4 | (3) |
q | long long | integer | 8 | (2), (3) |
Q | unsigned long long | integer | 8 | (2), (3) |
n | ssize_t | integer | (4) | |
N | size_t | integer | (4) | |
f | float | float | 4 | (5) |
d | double | float | 8 | (5) |
s | char[] | bytes | ||
p | char[] | bytes | ||
P | void * | integer | (6) |
緩沖區(qū)
將數(shù)據(jù)打包成二進(jìn)制通常是用在對(duì)性能要求很高的場(chǎng)景。
在這類場(chǎng)景中可以通過避免為每個(gè)打包結(jié)構(gòu)分配新緩沖區(qū)的開銷來優(yōu)化。
pack_into()和unpack_from()方法支持直接寫入預(yù)先分配的緩沖區(qū)。
import array import binascii import ctypes import struct s = struct.Struct('I 2s f') values = (1, 'ab'.encode('utf-8'), 2.7) print('原始值:', values) print() print('使用ctypes模塊string buffer') b = ctypes.create_string_buffer(s.size) print('原始buffer :', binascii.hexlify(b.raw)) s.pack_into(b, 0, *values) print('打包結(jié)果寫入 :', binascii.hexlify(b.raw)) print('解包 :', s.unpack_from(b, 0)) print() print('使用array模塊') a = array.array('b', b'\0' * s.size) print('原始值 :', binascii.hexlify(a)) s.pack_into(a, 0, *values) print('打包寫入 :', binascii.hexlify(a)) print('解包 :', s.unpack_from(a, 0))
# output
原始值: (1, b'ab', 2.7)使用ctypes模塊string buffer
原始buffer : b'000000000000000000000000'
打包結(jié)果寫入 : b'0100000061620000cdcc2c40'
解包 : (1, b'ab', 2.700000047683716)使用array模塊
原始值 : b'000000000000000000000000'
打包寫入 : b'0100000061620000cdcc2c40'
解包 : (1, b'ab', 2.700000047683716)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
python openCV實(shí)現(xiàn)攝像頭獲取人臉圖片
這篇文章主要為大家詳細(xì)介紹了python openCV實(shí)現(xiàn)攝像頭獲取人臉圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08Python運(yùn)維之獲取系統(tǒng)CPU信息的實(shí)現(xiàn)方法
今天小編就為大家分享一篇Python運(yùn)維之獲取系統(tǒng)CPU信息的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-06-06Python requests模塊cookie實(shí)例解析
這篇文章主要介紹了Python requests模塊cookie實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04基于Python+Matplotlib實(shí)現(xiàn)直方圖的繪制
Matplotlib是Python的繪圖庫,它能讓使用者很輕松地將數(shù)據(jù)圖形化,并且提供多樣化的輸出格式。本文將為大家介紹如何用matplotlib繪制直方圖,感興趣的朋友可以學(xué)習(xí)一下2022-04-04Python中實(shí)現(xiàn)地圖可視化的方法小結(jié)
Python提供了多個(gè)強(qiáng)大的庫,如Folium、Matplotlib、Geopandas等,使得創(chuàng)建漂亮而具有信息量的地圖變得簡(jiǎn)單而靈活,本文將詳細(xì)介紹如何使用這些庫繪制漂亮的地圖,感興趣的可以了解下2023-12-12在pytorch 中計(jì)算精度、回歸率、F1 score等指標(biāo)的實(shí)例
今天小編就為大家分享一篇在pytorch 中計(jì)算精度、回歸率、F1 score等指標(biāo)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-01-01python教程十行代碼教你語音轉(zhuǎn)文字QQ微信聊天
QQ上面發(fā)的語音消息是可以直接文字識(shí)別的,但是微信為什么沒有呢?是因?yàn)榧夹g(shù)太難實(shí)現(xiàn)嗎?這個(gè)很簡(jiǎn)單??!今天給大家介紹一下語音轉(zhuǎn)文字的原理2021-09-09