struct模塊

該模塊在Python值和表示為Python bytes對(duì)象的C結(jié)緩沖區(qū)構(gòu)體之間進(jìn)行轉(zhuǎn)換。可用于處理存儲(chǔ)在文件中或者來(lái)自網(wǎng)絡(luò)連接,以及其它來(lái)源的二進(jìn)制數(shù)據(jù)。它使用格式化字符串,作為C結(jié)構(gòu)體布局的簡(jiǎn)潔描述,以及從Python值,或者到Python值的預(yù)期轉(zhuǎn)換。

注意:默認(rèn)情況下,封裝給定的C結(jié)構(gòu)體的結(jié)構(gòu)包括填充字節(jié),以便為涉及的C類型保持正確的對(duì)齊;類似地,解包時(shí)會(huì)考慮對(duì)齊。選擇此行為使得被封裝的結(jié)構(gòu)體的字節(jié)完全對(duì)應(yīng)于C結(jié)構(gòu)體在內(nèi)存中的布局。要處理平臺(tái)無(wú)關(guān)的數(shù)據(jù)格式,或者忽略隱式的填充字節(jié),可以使用standard大小和對(duì)齊,代替native大小和對(duì)齊,查看字節(jié)順序,大小和對(duì)齊了解詳情。

有幾個(gè)struct函數(shù)(和Struct的方法)接收一個(gè)buffer參數(shù)。它引用實(shí)現(xiàn)了Buffer協(xié)議的對(duì)象,并提供一個(gè)可讀,或可讀寫(xiě)的緩存。用于該目的的最常見(jiàn)的類型是bytesbytearray,但是可以視為字節(jié)數(shù)組的許多其它類型實(shí)現(xiàn)了Buffer協(xié)議,因此它們可以讀和填充,而不需要額外的從bytes對(duì)象復(fù)制。

1 函數(shù)和異常

該模塊定義了以下異常和函數(shù):

1.1 異常 struct.error

在各種場(chǎng)合下拋出異常;參數(shù)是描述錯(cuò)誤的字符串。

1.2 struct.pack(fmt, v1, v2, ...)

根據(jù)格式化字符串fmt封裝,返回一個(gè)包括v1,v2等值的字節(jié)對(duì)象。參數(shù)必須與格式化所需的值完全匹配。

1.3 struct.pack_into(ftm, buffer, offset, v1, v2, ...)

根據(jù)格式化字符串fmt,封裝v1,v2等值,并從位置offset開(kāi)始,將封裝的字節(jié)寫(xiě)入可寫(xiě)緩沖區(qū)buffer中。注意,offset是必需的參數(shù)。

1.4 struct.unpack(fmt, buffer)

根據(jù)格式化字符串fmt,從緩沖區(qū)buffer(假設(shè)由pack(fmt, ...)封裝)中解包。即使結(jié)果只包含一項(xiàng),也是一個(gè)元組。緩沖區(qū)的大?。ㄒ宰止?jié)為單位)必需與格式所需的大小匹配,比如calcsize()所得的結(jié)果。

1.5 struct.unpack_from(fmt, buffer, offset=0)

根據(jù)格式化字符串fmt,從位置offset開(kāi)始解包。即使結(jié)果只包含一項(xiàng),也是一個(gè)元組。緩沖區(qū)的大小(以字節(jié)為單位)減去offset,至少是格式化所需的大小,比如calcsize()所得的結(jié)果。

1.5 struct.iter_unpack(fmt, buffer)

版本3.4中新增。

根據(jù)格式化字符串fmt,從緩沖區(qū)buffer中迭代解包。該函數(shù)返回一個(gè)iterator,它將從緩沖區(qū)中讀取大小相等的塊,直到所有內(nèi)容被耗盡。緩沖區(qū)的大小(以字節(jié)為單位)必須是格式化所需大小的倍數(shù),比如calcsize()所得的結(jié)果。

每次迭代yield一個(gè)由格式化字符串指定的元組。

1.6 struct.calcsize(fmt)

返回對(duì)應(yīng)于格式化字符串fmt的結(jié)構(gòu)體(以及由pack(fmt, ...)生成的字節(jié)對(duì)象)的大小。

2 格式化字符串

封裝和解包數(shù)據(jù)時(shí),格式化字符串是用于指定預(yù)期布局的機(jī)制。它們由Format Characters構(gòu)成,指定封裝和解包的數(shù)據(jù)類型。此外,還有一些特殊字符控制字節(jié)順序,大小和對(duì)齊。

2.1 字節(jié)順序,大小和對(duì)齊

默認(rèn)情況下,C語(yǔ)言類型以機(jī)器的本機(jī)格式和字節(jié)順序表示,如果需要(根據(jù)C編譯器使用的規(guī)則),跳過(guò)填充字節(jié),以便正確對(duì)齊。

或者根據(jù)下表,格式化字符串的第一個(gè)字符用于表明封裝數(shù)據(jù)的字節(jié)順序,大小和對(duì)齊:

字符 字節(jié)順序 大小 對(duì)齊
@ 本機(jī) 本機(jī) 本機(jī)
= 本機(jī) 標(biāo)準(zhǔn) 無(wú)
< 小端 標(biāo)準(zhǔn) 無(wú)
> 大端 標(biāo)準(zhǔn) 無(wú)
! 網(wǎng)絡(luò)(等于大端) 標(biāo)準(zhǔn) 無(wú)

如果第一個(gè)字符不是其中之一,則假定為“@”。

本地字節(jié)順序是大端或小端,這取決于主機(jī)系統(tǒng)。例如,Intel x86和AMD64(x86-64)是小端字節(jié)序;摩托羅拉68000和PowerPC G5是大端字節(jié)序;ARM和Intel Itanium可切換字節(jié)順序(雙字節(jié)順序)。使用sys.byteorder檢查系統(tǒng)的字節(jié)順序。

使用C編譯器的sizeof表達(dá)式確定本機(jī)大小和對(duì)齊。這總是與本機(jī)字節(jié)順序結(jié)合。

標(biāo)準(zhǔn)大小僅取決于格式化字符;參考格式化字符中的表格。

注意“@”和“=”之間的區(qū)別:都使用本機(jī)字節(jié)順序;但后者的大小和對(duì)齊是標(biāo)準(zhǔn)的。

“!”形式用于忘記網(wǎng)絡(luò)字節(jié)順序是大端還是小端的情況。

沒(méi)有辦法表示非本地字節(jié)順序(強(qiáng)制字節(jié)交換);使用適當(dāng)?shù)摹?lt;”或“>”。

注意:

  1. 填充僅在連續(xù)的結(jié)構(gòu)體成員之間自動(dòng)添加。在編碼的結(jié)構(gòu)體的開(kāi)頭或結(jié)尾不填充。
  2. 使用非本地大小和對(duì)齊時(shí),不添加填充,比如“<”,“>”,“=”和“!”。
  3. 要將結(jié)構(gòu)體結(jié)尾與特殊類型的對(duì)齊要求對(duì)齊,使用重復(fù)計(jì)數(shù)為0的該類型的代碼結(jié)束格式。

2.2 格式化字符

版本3.1中修改:在3.0中,有些整數(shù)格式封裝了超出范圍的值,并拋出DeprecationWarning代替struct.error。

版本3.2中修改:新增為非整數(shù)使用__index__()方法。

版本3.3中修改:添加“n”和“N”格式。

版本3.6中修改:添加“e”格式。

格式化字符有以下含義:C和Python值之間的轉(zhuǎn)換應(yīng)該明確指定類型?!皹?biāo)準(zhǔn)大小”列表示,使用標(biāo)準(zhǔn)大小時(shí),被封裝值的字節(jié)大??;也就是格式化字符串以“<”,“>”,“!”或“=”開(kāi)始時(shí)。當(dāng)使用本機(jī)大小,被封裝值的大小是平臺(tái)相關(guān)的。

格式 C類型 Python類型 標(biāo)準(zhǔn)大小 提示
x 填充字節(jié) 沒(méi)有值
c char 長(zhǎng)度為1的字節(jié) 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 integet 4
e 7 float 2 5
f float float 4 5
d double float 8 5
s char[] bytes
p char[] bytes
P void * integer 6

提示:

  1. “?”轉(zhuǎn)換碼對(duì)應(yīng)的_Bool類型由C99定義。如果該類型不可用,使用char模擬。在標(biāo)準(zhǔn)模式下,它總是由一個(gè)字節(jié)表示。
  2. 只有C編譯器支持long long類型,或者Windows上的__int64時(shí),“q”和“Q”轉(zhuǎn)換碼才在本機(jī)模式下可用。在標(biāo)準(zhǔn)模式下它們總是可用。
  3. 使用圖任何整數(shù)轉(zhuǎn)換碼封裝一個(gè)非整數(shù)時(shí),如果非整數(shù)有__index__()方法,則在封裝前會(huì)調(diào)用該方法把參數(shù)轉(zhuǎn)換為整數(shù)。
  4. “n”和“N”轉(zhuǎn)換只在本機(jī)大小中可用(選擇默認(rèn)或“@”字節(jié)順序)。對(duì)于標(biāo)準(zhǔn)大小,可用使用適合應(yīng)用程序的其它整數(shù)格式。
  5. 對(duì)于“f”,“d”和“e”轉(zhuǎn)換碼,封裝分別表示使用IEEE 754的binary32,binary64或binary16格式,而不管平臺(tái)使用的浮點(diǎn)數(shù)格式。
  6. “P”只在本機(jī)字節(jié)順序可用(選擇默認(rèn)或“@”字節(jié)順序)?!?”根據(jù)主機(jī)系統(tǒng)選擇使用小端或大端順序。struct模塊不會(huì)解釋為本機(jī)順序,因此“P”格式不可用。
  7. IEEE 754標(biāo)準(zhǔn)的2008版本中,引入了IEEE 754 binary16半精度。它有一個(gè)符號(hào)位,5位指數(shù)和11位精度(其中10位存儲(chǔ)),全精度可用表示大約6.1e-056.1e-05。C編譯器沒(méi)有廣泛支持該類型;在典型的機(jī)器中,unsigned short可用于存儲(chǔ),但不適合數(shù)據(jù)運(yùn)算。

可以在格式化字符之前使用整數(shù)表示重復(fù)次數(shù)。例如,“4h”完全等價(jià)于“hhhh”。

盡管次數(shù)和它的格式不可能包含空格,還是會(huì)忽略格式化字符之前的空格。

對(duì)于“s”格式化字符,次數(shù)表示字節(jié)的長(zhǎng)度,而不是其它格式化字符的重復(fù)次數(shù);例如,“10s”表示單個(gè)10個(gè)字節(jié)的字符串,“10c”表示10個(gè)字符。如果沒(méi)有指定次數(shù),默認(rèn)為1。對(duì)于封裝,字符串被截?cái)啵蛘哂每兆止?jié)填充,讓其正確適應(yīng)。對(duì)于解包,生成的字節(jié)對(duì)象總是指定的字節(jié)數(shù)。對(duì)于特殊情況,“0s”表示單個(gè)空字符串(“0c”表示0個(gè)字符)。

使用其中一個(gè)整數(shù)格式(“b”,“B”,“h”,“H”,“i”,“I”,“l(fā)”,“L”,“q”,“Q”)封裝值x的時(shí)候,如果x超出格式的有效返回,會(huì)拋出struct.error異常。

格式化字符“p”編碼一個(gè)Pascal string,表示一個(gè)short可變長(zhǎng)度的字符串存儲(chǔ)在固定字節(jié)數(shù)中,其長(zhǎng)度由次數(shù)指定。第一個(gè)字節(jié)存儲(chǔ)字符串的長(zhǎng)度,或者255,取兩者中的較小者。接著是字節(jié)的字符串。如果傳遞到pack()中的字符串太長(zhǎng)(長(zhǎng)于次數(shù)減1),則只存儲(chǔ)前count-1個(gè)字節(jié)。如果字符串比count-1短,則使用空字節(jié)填充,以便使用所有字節(jié)。注意,對(duì)應(yīng)unpack(),“p”格式化字符消耗count個(gè)字節(jié),但返回的字符串永遠(yuǎn)不會(huì)超過(guò)255個(gè)字節(jié)。

對(duì)于“?”格式化字符,返回值是TrueFalse。封裝時(shí),使用參數(shù)對(duì)象的真值。在本機(jī)或標(biāo)準(zhǔn)bool表示中,0或1會(huì)被封裝,解包時(shí)任何非0值是True。

2.3 示例

注意:所有示例假設(shè)本機(jī)字節(jié)順序和大小,以及大端機(jī)器對(duì)齊。

封裝/解包三個(gè)整數(shù)的基本示例:

>>> from struct import *
>>> pack('hhl', 1, 2, 3)
b'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('hhl')
8

解包的字段可以通過(guò)分配給變量,或者將結(jié)果包裝在命名元組中來(lái)命名:

>>> record = b'raymond  \x32\x12\x08\x01\x08'
>>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)

>>> from collections import namedtuple
>>> Student = namedtuple('Student', name serialnum school, gradelevel')
>>> Student._make(unpack('<10sHHb', record))
Student(name=b'raymond   ', serialnum=4658, school=264, gradelevel=8)

格式化字符的順序可能會(huì)對(duì)大小有影響,因?yàn)闈M足對(duì)齊需求的填充是不同的:

>>> pack('ci', b'*', 0x12131415)
b'*\x00\x00\x00\x12\x13\x14\x15'
>>> pack('ic', 0x12131415, b'*')
b'\x12\x13\x14\x15*'
>>> calcsize('ci')
8
>>> calcsize('ic')
5

下面的“11h01”格式,在結(jié)尾指定了兩個(gè)填充字節(jié),假設(shè)long在4字節(jié)邊界對(duì)齊:

>>> pack('11h01', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'

這只在本機(jī)大小和對(duì)齊有效時(shí)才其作用;標(biāo)準(zhǔn)大小和對(duì)齊不強(qiáng)制任何對(duì)齊。

3 類

struct模塊還定義了以下類型:

3.1 類struct.Struct(format)

返回一個(gè)新的Struct對(duì)象,更具格式化字符串format寫(xiě)入和讀取二進(jìn)制數(shù)據(jù)。創(chuàng)建一個(gè)Struct對(duì)象,并調(diào)用它的方法,比用同樣格式調(diào)用struct函數(shù)更高效,因?yàn)楦袷交址恍枰幾g一次。

編譯的Struct對(duì)象支持以下方法和屬性:

3.1.1 pack(v1, v2, ...)

完全等同于pack()函數(shù),使用編譯后的格式。(len(result)將會(huì)等于size

3.1.2 pack_into(buffer, offset, v1, v2, ...)

完全等同于pack_into()函數(shù),使用編譯后的格式。

3.1.3 unpack(buffer)

完全等同于unpack()函數(shù),使用編譯后的格式。緩沖區(qū)的大?。ㄒ宰止?jié)為單位)必須等于size

3.1.4 unpack_from(buffer, offset=0)

完全等同于unpack_from()函數(shù),使用編譯后的格式。緩沖區(qū)的大小減去offset(以字節(jié)為單位)必須至少為size

3.1.5 iter_unpack(buffer)

版本3.4中新增。

完全等同于iter_unpack()函數(shù),使用編譯后的格式。緩沖區(qū)的大?。ㄒ宰止?jié)為單位)必須是size的倍數(shù)。

3.1.6 format

構(gòu)造該Struct對(duì)象的格式化字符串。

3.1.7 size

對(duì)應(yīng)于format的結(jié)構(gòu)體(以及由pack(fmt, ...)生成的字節(jié)對(duì)象)的大小。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容