struct --- 將位元組直譯為打包起來的二進位資料¶
原始碼:Lib/struct.py
此模組可在 Python 數值與以 Python bytes 物件表示的 C 結構之間進行轉換。簡潔的格式字串描述了與 Python 數值之間預期的轉換。此模組的函式和物件可用於兩種截然不同的應用程式:與外部來源(檔案或網路連線)的資料交換,或是 Python 應用程式與 C 層之間的資料傳輸。
備註
當未給定前綴字元時會預設為原生模式。它會根據建構 Python 直譯器的平台和編譯器來打包或解包資料。打包給定 C 結構的結果包含填充位元組,以維持相關 C 型別的正確對齊;同樣地,解包時也會考量對齊。相反地,當在外部來源之間傳輸資料時,程式設計師需負責定義位元組順序和元素之間的填充。詳情請參見 位元組順序、大小和對齊。
一些 struct 函式(和 Struct 的方法)接受一個 buffer 引數。這是指實作緩衝協定 (Buffer Protocol) 並提供可讀或可讀寫緩衝區的物件。最常用於此目的的型別是 bytes 和 bytearray,但許多其他可以視為位元組陣列的型別都實作了緩衝區協定,因此它們可以從 bytes 物件讀取或填入資料而無需額外的複製。
函式與例外¶
此模組定義了以下例外和函式:
- exception struct.error¶
在各種情況下都可能觸發的例外;引數是一個描述錯誤內容的字串。
- struct.pack(format, v1, v2, ...)¶
回傳一個包含依照格式字串 format 打包的數值 v1、v2、... 的位元組物件。引數必須完全符合格式所需的數值。
- struct.pack_into(format, buffer, offset, v1, v2, ...)¶
依照格式字串 format 打包數值 v1、v2、...,並將打包後的位元組寫入可寫緩衝區 buffer 中從位置 offset 開始的地方。請注意 offset 是必要的引數。
- struct.unpack(format, buffer)¶
根據格式字串 format 從緩衝區 buffer(推測是由
pack(format, ...)打包的)解包。結果是一個元組,即使它只包含一個項目。緩衝區的位元組大小必須符合格式所需的大小,如calcsize()所示。
- struct.unpack_from(format, /, buffer, offset=0)¶
根據格式字串 format 從 buffer 的 offset 位置開始解包。即使它只包含一個項目,結果也都是一個元組。緩衝區從位置 offset 開始的位元組大小,必須至少達到格式所需的大小,如
calcsize()所示。
- struct.iter_unpack(format, buffer)¶
根據格式字串 format 疊代地從緩衝區 buffer 解包。此函式回傳一個疊代器,它會從緩衝區讀取等大小的區塊,直到消耗完所有內容。緩衝區的位元組大小必須是格式所需大小的倍數,如
calcsize()所示。每次疊代都會產生 (yield) 出一個由格式字串指定的元組。
在 3.4 版被加入.
- struct.calcsize(format)¶
回傳對應於格式字串 format 的結構大小(因此也是
pack(format, ...)所產生的位元組物件的大小)。
格式字串¶
Format strings describe the data layout when packing and unpacking data. They are built up from type codes, which specify the type of data being packed/unpacked. In addition, special characters control the byte order, size and alignment. Each format string consists of an optional prefix character which describes the overall properties of the data and one or more format characters which describe the actual data values and padding.
位元組順序、大小和對齊¶
預設情況下,C 型別以機器的原生格式和位元組順序表示,並在必要時透過跳過填充位元組來正確對齊(根據 C 編譯器所使用的規則)。選擇此行為使得打包結構的位元組完全對應於相對應 C 結構的記憶體配置。是否使用原生位元組順序和填充或標準格式取決於應用程式。
或者,格式字串的第一個字元可以用來指示打包資料的位元組順序、大小和對齊,如下表所示:
字元 |
位元組順序 |
大小 |
對齊 |
|---|---|---|---|
|
原生 |
原生 |
原生 |
|
原生 |
標準 |
無 |
|
小端序 |
標準 |
無 |
|
大端序 |
標準 |
無 |
|
網路(= 大端序) |
標準 |
無 |
如果第一個字元不是這些字元之一,則假設為 '@'。
備註
數字 1023(十六進位為 0x3ff)具有以下位元組表示法:
大端序(
>)為03 ff小端序(
<)為ff 03
Python 範例:
>>> import struct
>>> struct.pack('>h', 1023)
b'\x03\xff'
>>> struct.pack('<h', 1023)
b'\xff\x03'
原生位元組順序是大端序或小端序,會取決於主機系統。例如,Intel x86、AMD64 (x86-64)和 Apple M1 是小端序;IBM z 和許多舊架構是大端序。可使用 sys.byteorder 來檢查你系統的位元組順序。
原生大小和對齊是使用 C 編譯器的 sizeof 運算式來決定的。這總是與原生位元組順序結合使用。
Standard size depends only on the type code; see the table in the Type Codes section.
請注意 '@' 和 '=' 之間的差異:兩者都使用原生位元組順序,但後者的大小和對齊是標準化的。
'!' 形式表示網路位元組順序,根據 IETF RFC 1700 的定義,它總是大端序。
沒有方法來指示非原生位元組順序(強制位元組交換);請使用適當的 '<' 或 '>' 選擇。
註解:
填充只會在連續的結構成員之間自動加入。編碼結構的開頭或結尾不會加入填充。
使用非原生大小和對齊時,例如使用 '<'、'>'、'=' 和 '!' 時,不會加入填充。
要將結構的結尾對齊到特定型別的對齊需求,請以該型別的碼結束格式,重複次數為零。請參見範例。
Type Codes¶
Type codes (or format codes) have the following meaning; the conversion between C and
Python values should be obvious given their types. The 'Standard size' column
refers to the size of the packed value in bytes when using standard size; that
is, when the format string starts with one of '<', '>', '!' or
'='. When using native size, the size of the packed value is
platform-dependent.
格式 |
C Type |
Python 型別 |
標準大小 |
註解 |
|---|---|---|---|---|
|
填充位元組 |
無值 |
(7) |
|
|
char |
長度為 1 的位元組 |
1 |
|
|
signed char |
int |
1 |
(2) |
|
unsigned char |
int |
1 |
(2) |
|
_Bool |
bool |
1 |
(1) |
|
short |
int |
2 |
(2) |
|
unsigned short |
int |
2 |
(2) |
|
int |
int |
4 |
(2) |
|
unsigned int |
int |
4 |
(2) |
|
long |
int |
4 |
(2) |
|
unsigned long |
int |
4 |
(2) |
|
long long |
int |
8 |
(2) |
|
unsigned long long |
int |
8 |
(2) |
|
|
int |
(2), (3) |
|
|
|
int |
(2), (3) |
|
|
_Float16 |
float |
2 |
(4), (6) |
|
float |
float |
4 |
(4) |
|
double |
float |
8 |
(4) |
|
float complex |
complex |
8 |
(10) |
|
double complex |
complex |
16 |
(10) |
|
float complex |
complex |
8 |
(10) |
|
double complex |
complex |
16 |
(10) |
|
char[] |
位元組 |
(9) |
|
|
char[] |
位元組 |
(8) |
|
|
void* |
int |
(2), (5) |
在 3.3 版的變更: 新增 'n' 與 'N' 格式的支援。
在 3.6 版的變更: 新增 'e' 格式的支援。
在 3.14 版的變更: 新增 'F' 與 'D' 格式的支援。
在 3.15 版的變更: Added support for the 'Zf' and 'Zd' formats.
也參考
The array and ctypes modules,
as well as third-party modules like numpy,
use similar -- but slightly different -- type codes.
註解:
'?'轉換碼對應於自 C99 以來 C 標準定義的 _Bool 型別。在標準模式下,它由一個位元組表示。當嘗試使用任何整數轉換碼打包非整數時,如果非整數具有
__index__()方法,則會呼叫該方法在打包之前將引數轉換為整數。在 3.2 版的變更: 新增對非整數使用
__index__()方法的支援。'n'和'N'轉換碼僅適用於原生大小(作為預設選擇或使用'@'位元組順序字元)。對於標準大小,你可以使用適合你應用程式的其他整數格式。對於
'f'、'd'和'e'轉換碼,打包表示法使用 IEEE 754 binary32、binary64 或 binary16 格式(分別對應於'f'、'd'或'e'),無論平台使用何種浮點數格式。The
'P'type code is only available for the native byte ordering (selected as the default or with the'@'byte order character). The byte order character'='chooses to use little- or big-endian ordering based on the host system. The struct module does not interpret this as native ordering, so the'P'format is not available.IEEE 754 binary16「半精度 (half precision)」型別是在 2008 年的 IEEE 754 標準修訂版中引入的。它有一個符號位元 (sign bit)、5 位元指數和 11 位元精度(明確儲存 10 位元),可以全精度表示大約
6.1e-05到6.5e+04之間的數字。此型別未被 C 編譯器廣泛支援:若編譯器支援 C23 標準的附錄 H,則可以作為 _Float16 型別使用。在典型機器上,unsigned short 可以用於儲存但不能用於數學運算。請參見 Wikipedia 上的半精度浮點數格式頁面以取得更多資訊。打包時,
'x'插入一個 NUL 位元組。The
'p'type code encodes a "Pascal string", meaning a short variable-length string stored in a fixed number of bytes, given by the count. The first byte stored is the length of the string, or 255, whichever is smaller. The bytes of the string follow. If the byte string passed in topack()is too long (longer than the count minus 1), only the leadingcount-1bytes of the string are stored. If the byte string is shorter thancount-1, it is padded with null bytes so that exactly count bytes in all are used. Note that forunpack(), the'p'type code consumescountbytes, but that thebytesobject returned can never contain more than 255 bytes. When packing, arguments of typesbytesandbytearrayare accepted.For the
's'type code, the count is interpreted as the length of the byte string, not a repeat count like for the other type codes; for example,'10s'means a single 10-byte string mapping to or from a single Python byte string, while'10c'means 10 separate one byte character elements (e.g.,cccccccccc) mapping to or from ten different Python byte objects. (See 範例 for a concrete demonstration of the difference.) If a count is not given, it defaults to 1. For packing, the byte string is truncated or padded with null bytes as appropriate to make it fit. For unpacking, the resultingbytesobject always has exactly the specified number of bytes. As a special case,'0s'means a single, empty byte string (while'0c'means 0 characters). When packing, arguments of typesbytesandbytearrayare accepted.For the
'F'and'D'type codes, the packed representation uses the IEEE 754 binary32 and binary64 format for components of the complex number, regardless of the floating-point format used by the platform. Note that complex types (F/ZfandD/Zd) are available unconditionally, despite complex types being an optional feature in C. As specified in the C11 standard, each complex type is represented by a two-element C array containing, respectively, the real and imaginary parts.
A type code may be preceded by an integral repeat count. For example,
the format string '4h' means exactly the same as 'hhhh'.
格式之間的空白字元會被忽略;但是計數和其格式不能包含空白字元。
當使用整數格式之一('b'、'B'、'h'、'H'、'i'、'I'、'l'、'L'、'q'、'Q')打包數值 x 時,如果 x 超出該格式的有效範圍,則會觸發 struct.error。
在 3.1 版的變更: 以前一些整數格式會環繞超出範圍的數值並引發 DeprecationWarning 而不是 struct.error。
For the '?' type code, the return value is either True or
False. When packing, the truth value of the argument object is used.
Either 0 or 1 in the native or standard bool representation will be packed, and
any non-zero value will be True when unpacking.
範例¶
備註
原生位元組順序範例(由 '@' 格式前綴或缺少任何前綴字元指定)可能與讀者機器產生的結果不符,因為這取決於平台和編譯器。
使用大端序打包和解包三種不同大小的整數:
>>> from struct import *
>>> pack(">bhl", 1, 2, 3)
b'\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('>bhl', b'\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('>bhl')
7
嘗試打包對於定義欄位來說太大的整數:
>>> pack(">h", 99999)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
struct.error: 'h' format requires -32768 <= number <= 32767
示範 's' 和 'c' 格式字元之間的差異:
>>> pack("@ccc", b'1', b'2', b'3')
b'123'
>>> pack("@3s", b'123')
b'123'
解包的欄位可以透過將其指派給變數或將結果包裝在具名元組中來命名:
>>> 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)
The ordering of type codes may have an impact on size in native
mode since padding is implicit. In standard mode, the user is
responsible for inserting any desired padding.
Note in
the first pack call below that three NUL bytes were added after the
packed '#' to align the following integer on a four-byte boundary.
In this example, the output was produced on a little endian machine:
>>> pack('@ci', b'#', 0x12131415)
b'#\x00\x00\x00\x15\x14\x13\x12'
>>> pack('@ic', 0x12131415, b'#')
b'\x15\x14\x13\x12#'
>>> calcsize('@ci')
8
>>> calcsize('@ic')
5
假設平台的 long 對齊到 4 位元組邊界,以下格式 'llh0l' 會在結尾加入兩個填充位元組:
>>> pack('@llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'
應用¶
struct 模組有兩種主要應用程式:在應用程式內或使用相同編譯器編譯的另一個應用程式之間進行 Python 和 C 程式碼的資料交換(原生格式),以及使用約定資料配置的應用程式之間的資料交換(標準格式)。一般來說,為這兩個領域建構的格式字串是不同的。
原生格式¶
When constructing format strings which mimic native layouts, the
compiler and machine architecture determine byte ordering and padding.
In such cases, the @ format character should be used to specify
native byte ordering and data sizes. Internal pad bytes are normally inserted
automatically. It is possible that a zero-repeat type code will be
needed at the end of a format string to round up to the correct
byte boundary for proper alignment of consecutive chunks of data.
考慮這兩個簡單範例(在 64 位元小端序機器上):
>>> calcsize('@lhl')
24
>>> calcsize('@llh')
18
在第二個格式字串的結尾,如果不使用額外填充,資料不會填充到 8 位元組邊界。零重複格式碼解決了這個問題:
>>> calcsize('@llh0l')
24
The 'x' type code can be used to specify the repeat, but for
native formats it is better to use a zero-repeat format like '0l'.
預設使用原生位元組順序和對齊,但最好明確使用 '@' 前綴字元。
標準格式¶
當與你的行程之外的網路或儲存區等交換資料時,要夠精確。指定確切的位元組順序、大小和對齊。不要假設它們與特定機器的原生順序匹配。例如,網路位元組順序是大端序,而許多流行的 CPU 是小端序。透過明確定義這一點,使用者無需關心其程式碼運行的平台細節。第一個字元通常應該是 < 或 >(或 !)。填充是程式設計師的責任。零重複格式字元不會起作用。取而代之的是使用者必須在需要的地方明確加入 'x' 填充位元組。重新檢視上一節的範例,我們有:
>>> calcsize('<qh6xq')
24
>>> pack('<qh6xq', 1, 2, 3) == pack('@lhl', 1, 2, 3)
True
>>> calcsize('@llh')
18
>>> pack('@llh', 1, 2, 3) == pack('<qqh', 1, 2, 3)
True
>>> calcsize('<qqh6x')
24
>>> calcsize('@llh0l')
24
>>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3)
True
上述結果(在 64 位元機器上執行)和在不同機器上執行時不保證會匹配。例如,下面的範例是在 32 位元機器上執行的:
>>> calcsize('<qqh6x')
24
>>> calcsize('@llh0l')
12
>>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3)
False
類別¶
struct 模組也定義了以下型別:
- class struct.Struct(format)¶
回傳一個新的 Struct 物件,它會根據格式字串 format 寫入和讀取二進位資料。建立一次
Struct物件並呼叫其方法比使用相同格式呼叫模組層級函式更有效率,因為格式字串只編譯一次。備註
傳遞給模組層級函式的最近一個格式字串的編譯版本會被快取起來,因此僅使用少數格式字串的程式無需擔心重複使用單一
Struct實例。編譯過的 Struct 物件支援以下方法和屬性:
- pack_into(buffer, offset, v1, v2, ...)¶
與
pack_into()函式相同,會使用編譯過的格式。
- unpack_from(buffer, offset=0)¶
與
unpack_from()函式相同,會使用編譯過的格式。緩衝區從位置 offset 開始的位元組大小必須至少為size。
- iter_unpack(buffer)¶
與
iter_unpack()函式相同,會使用編譯過的格式。緩衝區的位元組大小必須是size的倍數。在 3.4 版被加入.
- format¶
用於建構此 Struct 物件的格式字串。
在 3.13 版的變更: 結構的 repr() 已經改變。現在是:
>>> Struct('i') Struct('i')