struct --- バイト列をパックされたバイナリデータとして解釈する

ソースコード: Lib/struct.py


このモジュールは、Python の値と、Python の bytes オブジェクトで表した C の構造体との間の変換を行います。 簡潔な 書式文字列 で、Python の値との変換方法を記述します。 このモジュールの関数とオブジェクトには、大きく分けて 2 つの用途があります。 外部のデータ源 (ファイルやネットワーク接続) とのデータ交換と、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 は必須の引数です。 負の offset は buffer の末尾から数えます。

struct.unpack(format, buffer)

(pack(format, ...) でパックされたであろう) バッファ buffer を、書式文字列 format に従ってアンパックします。 値が一つしかない場合を含め、結果はタプルで返されます。 バッファのバイトサイズは、 calcsize() の返り値である書式文字列が要求するサイズと一致しなければなりません。

struct.unpack_from(format, /, buffer, offset=0)

書式文字列 format に従い、buffer の位置 offset からアンパックします。 結果は、要素が 1 つだけでもタプルになります。 位置 offset から先のバッファのバイト数は、書式が必要とするサイズ (calcsize() の戻り値) 以上でなければなりません。 負の offset は buffer の末尾から数えます。

struct.iter_unpack(format, buffer)

バッファ buffer を、書式文字列 format に従ってイテレータ形式でアンパックします。 この関数が返すイテレータは、すべての内容を読み終わるまでバッファから一定の大きさのチャンクを読み取ります。 バッファのバイトサイズは、 calcsize() の返り値である書式文字列が要求するサイズの倍数でなければなりません。

イテレーション毎に書式文字列で指定されたタプルを yield します。

Added in version 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 の構造体のメモリ配置と正確に一致します。 ネイティブのバイトオーダとパディングを使うか、標準の形式を使うかは用途によります。

これに代わって、フォーマット文字列の最初の文字を使って、バイトオーダやサイズ、アラインメントを指定することができます。指定できる文字を以下のテーブルに示します:

文字

バイトオーダ

サイズ

アラインメント

@

native

native

native

=

native

standard

none

<

リトルエンディアン

standard

none

>

ビッグエンディアン

standard

none

!

ネットワーク (= ビッグエンディアン)

standard

none

フォーマット文字列の最初の文字が上のいずれかでない場合、'@' であるとみなされます。

注釈

数値 1023 (16 進数では 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 で定義されているとおり、常にビッグエンディアンです。

バイトオーダに関して、「(強制的にバイトスワップを行う)ネイティブの逆」を指定する方法はありません。'<' または '>' のうちふさわしい方を選んでください。

注釈:

  1. パディングは構造体のメンバの並びの中にだけ自動で追加されます。最初や最後にパディングが追加されることはありません。

  2. ネイティブでないサイズおよびアラインメントが使われる場合にはパディングは行われません (たとえば '<', '>', '=', '!' を使った場合です)。

  3. 特定の型によるアラインメント要求に従うように構造体の末端をそろえるには、繰り返し回数をゼロにした特定の型でフォーマットを終端します。 使用例 を参照して下さい。

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 の型

Python の型

標準のサイズ

注釈

x

パディングバイト

値なし

(7)

c

char

長さ 1 のバイト列

1

b

signed char

整数

1

(2)

B

unsigned char

整数

1

(2)

?

_Bool

真偽値型(bool)

1

(1)

h

short

整数

2

(2)

H

unsigned short

整数

2

(2)

i

int

整数

4

(2)

I

unsigned int

整数

4

(2)

l

long

整数

4

(2)

L

unsigned long

整数

4

(2)

q

long long

整数

8

(2)

Q

unsigned long long

整数

8

(2)

n

ssize_t

整数

(2), (3)

N

size_t

整数

(2), (3)

e

_Float16

浮動小数点数

2

(4), (6)

f

float

浮動小数点数

4

(4)

d

double

浮動小数点数

8

(4)

Zf

float complex

複素数

8

(10)

Zd

double complex

複素数

16

(10)

s

char[]

bytes

(9)

p

char[]

bytes

(8)

P

void*

整数

(2), (5)

バージョン 3.3 で変更: 'n' および 'N' フォーマットのサポートが追加されました。

バージョン 3.6 で変更: 'e' フォーマットのサポートが追加されました。

バージョン 3.14 で変更: 'F' と 'D' の書式がサポートされました。

バージョン 3.15 で変更: 'Zf' と 'Zd' の書式がサポートされました。 'F' と 'D' の書式は 緩やかに非推奨 になりました。

参考

array モジュール、ctypes モジュール、numpy などのサードパーティーモジュールでも、似ていますが少し異なる型コードを使います。

注釈:

  1. '?' 変換コードは、C99 以降の C 規格で定義されている _Bool 型に対応します。 標準モードでは 1 バイトで表します。

  2. 整数の変換コードで整数以外の値をパックしようとした場合、その値に __index__() メソッドがあれば、パックする前にそのメソッドを呼び出して引数を整数に変換します。

    バージョン 3.2 で変更: 整数以外の値に対して __index__() メソッドを使うようになりました。

  3. 'n' および 'N' 変換コードは (デフォルトもしくはバイトオーダ文字 '@' 付きで選択される) native サイズ使用時のみ利用できます。standard サイズ使用時には、自身のアプリケーションに適する他の整数フォーマットを使うことができます。

  4. 'f' 、 'd' および 'e' 変換コードについて、パックされた表現は IEEE 754 binary32 ('f' の場合) 、 binary64 ('d' の場合) 、またはbinary16('e' の場合) フォーマットが、プラットフォームにおける浮動小数点数のフォーマットに関係なく使われます。

  5. 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.

  6. IEEE 754 の binary16「半精度」型は、IEEE 754 規格 の 2008 年の改訂で導入されました。 符号ビット、5 ビットの指数部、11 ビットの精度 (明示的に格納するのは 10 ビット) を持ち、およそ 6.1e-05 から 6.5e+04 までの数を完全な精度で表せます。 この型は C コンパイラでは広くサポートされていません。 C23 規格の附属書 H をサポートするコンパイラなら、_Float16 型として利用できます。 一般的なマシンでは unsigned short を格納に使えますが、算術演算には使えません。 詳しくは Wikipedia の 半精度浮動小数点数形式 のページを参照してください。

  7. パック時に 'x' は NUL バイトを 1 つ挿入します。

  8. 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 to pack() is too long (longer than the count minus 1), only the leading count-1 bytes of the string are stored. If the byte string is shorter than count-1, it is padded with null bytes so that exactly count bytes in all are used. Note that for unpack(), the 'p' type code consumes count bytes, but that the bytes object returned can never contain more than 255 bytes. When packing, arguments of types bytes and bytearray are accepted.

  9. 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 resulting bytes object 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 types bytes and bytearray are accepted.

  10. 'Zf' と 'Zd' 型コードでは、プラットフォームで使う浮動小数点数形式にかかわらず、複素数の各成分をそれぞれ IEEE 754 の binary32 と binary64 の形式でパックします。 C では複素数型は任意の機能ですが、ここでは無条件に利用できます。 C11 規格の定義どおり、各複素数型は実部と虚部をこの順で含む 2 要素の C の配列で表します。 互換性のため、'F' と 'D' 書式指定文字もサポートされます (それぞれ 'Zf' と 'Zd' に対応します)。

A type code may be preceded by an integral repeat count. For example, the format string '4h' means exactly the same as 'hhhh'.

フォーマット文字間の空白文字は無視されます; count とフォーマット文字の間にはスペースを入れてはいけません。

整数フォーマット ('b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q') のいずれかを使って値 x をパックするとき x がフォーマットの適切な値の範囲に無い場合、 struct.error が送出されます。

バージョン 3.1 で変更: 以前は、一部の整数フォーマットでは範囲外の値を範囲内に折り返し、struct.error の代わりに DeprecationWarning を送出していました。

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.

使用例

注釈

ネイティブのバイトオーダを使う例 (書式の接頭文字が '@'、または接頭文字がない場合) の結果は、プラットフォームとコンパイラに依存するため、読者のマシンでの結果と一致しないことがあります。

ビッグエンディアンで、3 種類のサイズの整数をパック、アンパックします。

>>> 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'

アンパックした結果のフィールドは、変数に割り当てるか named tuple でラップすることによって名前を付けることができます:

>>> 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

以下の書式 'llh0l' では、このプラットフォームの long が 4 バイト境界に配置されるとすると、末尾にパディングバイトが 2 つ追加されます。

>>> pack('@llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'

参考

array モジュール

一様なデータ型からなるバイナリ記録データのパック。

json モジュール

JSON のエンコーダーとデコーダー。

pickle モジュール

Python オブジェクトのシリアライズ。

アプリケーション

struct モジュールの主な用途は 2 つあります。 1 つは、同じアプリケーション内、または同じコンパイラでコンパイルした別のアプリケーションとの間で、Python と C のコードがデータを交換する用途です (ネイティブの形式)。 もう 1 つは、合意したデータ配置を使ってアプリケーション間でデータを交換する用途です (標準の形式)。 一般に、この 2 つの用途では異なる書式文字列を作ります。

ネイティブの形式

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 ビットのリトルエンディアンのマシンで、次の 2 つの簡単な例を考えます。

>>> calcsize('@lhl')
24
>>> calcsize('@llh')
18

2 番目の書式文字列では、パディングを追加しない限り、データの末尾は 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)

フォーマット文字列 format に従ってバイナリデータを読み書きする、新しい Struct オブジェクトを返します。 Struct オブジェクトを一度作ってからそのメソッドを呼び出すと、フォーマット文字列のコンパイルが一度だけになるので、モジュールレベルの関数を同じフォーマットで呼び出すよりも効率的です。

注釈

モジュールレベルの関数に渡した直近の書式文字列は、コンパイル済みのものがキャッシュされます。 そのため、少数の書式文字列しか使わないプログラムでは、1 つの Struct インスタンスを再利用することを気にする必要はありません。

コンパイルされた Struct オブジェクトは以下のメソッドと属性をサポートします:

pack(v1, v2, ...)

pack() 関数と同じ、コンパイルされたフォーマットを利用するメソッドです。 (len(result) は size と等しいでしょう)

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

pack_into() 関数と同じ、コンパイルされたフォーマットを利用するメソッドです。

unpack(buffer)

unpack() 関数と同じ、コンパイルされたフォーマットを利用するメソッドです。 (buffer のバイト数は size と等しくなければなりません)。

unpack_from(buffer, offset=0)

unpack_from() 関数と同じ、コンパイルされたフォーマットを利用するメソッドです。 (offset を始点とする buffer のバイト数は少なくとも size 以上でなければなりません)。

iter_unpack(buffer)

iter_unpack() 関数と同じ、コンパイルされたフォーマットを利用するメソッドです。 (buffer のバイト数は size の倍数でなければなりません)。

Added in version 3.4.

format

この Struct オブジェクトを作成する時に利用されたフォーマット文字列です。

バージョン 3.7 で変更: 書式文字列の型が bytes から str に変更されました。

size

format 属性に対応する構造体の (従って pack() メソッドによって作成されるバイト列オブジェクトの) サイズです。

バージョン 3.13 で変更: 構造体の repr() が変更されました。 現在は次の形式です:

>>> Struct('i')
Struct('i')