7.1. struct --- バイト列をパックされたバイナリデータとして解釈する¶
ソースコード: Lib/struct.py
このモジュールは、 Python の値と Python bytes オブジェクトとして表される C の構造体データとの間の変換を実現します。このモジュールは特に、ファイルに保存されたり、ネットワーク接続を経由したバイナリデータを扱うときに使われます。このモジュールでは、C 構造体のレイアウトおよび Python の値との間で行いたい変換をコンパクトに表現するために、 書式文字列 を使います。
注釈
デフォルトでは、与えられた C の構造体をパックする際に、関連する C データ型を適切にアラインメント(alignment)するために数バイトのパディングを行うことがあります。この挙動が選択されたのは、パックされた構造体のバイト表現を対応する C 構造体のメモリレイアウトに正確に対応させるためです。プラットフォーム独立のデータフォーマットを扱ったり、隠れたパディングを排除したりするには、サイズ及びアラインメントとして native の代わりに standard を使うようにします: 詳しくは バイトオーダ、サイズ、アラインメント を参照して下さい。
いくつかの struct の関数 (および Struct のメソッド) は buffer 引数を取ります。 これは バッファプロトコル (buffer Protocol) を実装していて読み取り可能または読み書き可能なバッファを提供するオブジェクトのことです。この目的のために使われる最も一般的な型は bytes と bytearray ですが、バイトの配列とみなすことができるような他の多くの型がバッファプロトコルを実装しています。そのため、それらは bytes オブジェクトから追加のコピーなしで読み出しや書き込みができます。
7.1.1. 関数と例外¶
このモジュールは以下の例外と関数を定義しています:
-
exception
struct.error¶ 様々な状況で送出される例外です。引数は何が問題なのかを記述する文字列です。
-
struct.pack(fmt, v1, v2, ...)¶ フォーマット文字列 fmt に従い値 v1, v2, ... をパックして、バイト列オブジェクトを返します。引数は指定したフォーマットが要求する型と正確に一致していなければなりません。
-
struct.pack_into(fmt, buffer, offset, v1, v2, ...)¶ フォーマット文字列 fmt に従い値 v1, v2, ... をパックしてバイト列にし、書き込み可能な buffer のオフセット offset 位置より書き込みます。オフセットは省略出来ません。
-
struct.unpack(fmt, buffer)¶ (
pack(fmt, ...)でパックされたであろう) バッファ buffer を、書式文字列 fmt に従ってアンパックします。 値が一つしかない場合を含め、結果はタプルで返されます。 バッファのバイトサイズは、calcsize()の返り値である書式文字列が要求するサイズと一致しなければなりません。
-
struct.unpack_from(fmt, buffer, offset=0)¶ バッファ buffer を、 offset の位置から書式文字列 fmt に従ってアンパックします。 値が一つしかない場合を含め、結果はタプルで返されます。 バッファのバイトサイズから offset を引いたものは、少なくとも
calcsize()の返り値である書式文字列が要求するサイズでなければなりません。
-
struct.iter_unpack(fmt, buffer)¶ バッファ buffer を、書式文字列 fmt に従ってイテレータ形式でアンパックします。 この関数が返すイテレータは、すべての内容を読み終わるまでバッファから一定の大きさのチャンクを読み取ります。 バッファのバイトサイズは、
calcsize()の返り値である書式文字列が要求するサイズの倍数でなければなりません。イテレーション毎に書式文字列で指定されたタプルを yield します。
バージョン 3.4 で追加.
-
struct.calcsize(fmt)¶ 書式文字列 fmt に従って、構造体 (それと
pack(fmt, ...)によって作成されるバイト列オブジェクト) のサイズを返します。
7.1.2. 書式文字列¶
書式文字列はデータをパックしたりアンパックしたりするときの期待されるレイアウトを指定するためのメカニズムです。文字列はパック/アンパックされるデータの型を指定する 書式指定文字 から組み立てられます。さらに、 バイトオーダ、サイズ、アラインメント を制御するための特殊文字もあります。
7.1.2.1. バイトオーダ、サイズ、アラインメント¶
デフォルトでは、C での型はマシンのネイティブ (native) の形式およびバイトオーダ (byte order) で表され、適切にアラインメント (alignment) するために、必要に応じて数バイトのパディングを行ってスキップします (これは C コンパイラが用いるルールに従います)。
これに代わって、フォーマット文字列の最初の文字を使って、バイトオーダやサイズ、アラインメントを指定することができます。指定できる文字を以下のテーブルに示します:
文字 |
バイトオーダ |
サイズ |
アラインメント |
|---|---|---|---|
|
native |
native |
native |
|
native |
standard |
none |
|
リトルエンディアン |
standard |
none |
|
ビッグエンディアン |
standard |
none |
|
ネットワーク (= ビッグエンディアン) |
standard |
none |
フォーマット文字列の最初の文字が上のいずれかでない場合、'@' であるとみなされます。
ネイティブのバイトオーダはビッグエンディアンかリトルエンディアンで、ホスト計算機に依存します。例えば、Intel x86 および AMD64 (x86-64) はリトルエンディアンです。Motorola 68000 および PowerPC G5 はビッグエンディアンです。ARM および Intel Itanium はエンディアンを切り替えられる機能を備えています (バイエンディアン)。使っているシステムでのエンディアンは sys.byteorder を使って調べて下さい。
ネイティブのサイズおよびアラインメントは C コンパイラの sizeof 式で決定されます。ネイティブのサイズおよびアラインメントはネイティブのバイトオーダと同時に使われます。
標準のサイズはフォーマット文字だけで決まります。 書式指定文字 の表を参照して下さい。
'@' と '=' の違いに注意してください: 両方ともネイティブのバイトオーダですが、後者のバイトサイズとアラインメントは標準のものに合わせてあります。
'!' 表記は、ネットワークバイトオーダがビッグエンディアンかリトルエンディアンか忘れてしまったという不運な方のために用意されています。
バイトオーダに関して、「(強制的にバイトスワップを行う)ネイティブの逆」を指定する方法はありません。'<' または '>' のうちふさわしい方を選んでください。
注釈:
パディングは構造体のメンバの並びの中にだけ自動で追加されます。最初や最後にパディングが追加されることはありません。
ネイティブでないサイズおよびアラインメントが使われる場合にはパディングは行われません (たとえば '<', '>', '=', '!' を使った場合です)。
特定の型によるアラインメント要求に従うように構造体の末端をそろえるには、繰り返し回数をゼロにした特定の型でフォーマットを終端します。 使用例 を参照して下さい。
7.1.2.2. 書式指定文字¶
フォーマット文字 (format character) は以下の意味を持っています; C と Python の間の変換では、値は正確に以下に指定された型でなくてはなりません: 「標準のサイズ」列は standard サイズ使用時にパックされた値が何バイトかを示します。つまり、フォーマット文字列が '<', '>', '!', '=' のいずれかで始まっている場合のものです。native サイズ使用時にはパックされた値の大きさはプラットフォーム依存です。
フォーマット |
C の型 |
Python の型 |
標準のサイズ |
注釈 |
|---|---|---|---|---|
|
パディングバイト |
値なし |
||
|
|
長さ 1 のバイト列 |
1 |
|
|
|
整数 |
1 |
(1),(3) |
|
|
整数 |
1 |
(3) |
|
|
真偽値型(bool) |
1 |
(1) |
|
|
整数 |
2 |
(3) |
|
|
整数 |
2 |
(3) |
|
|
整数 |
4 |
(3) |
|
|
整数 |
4 |
(3) |
|
|
整数 |
4 |
(3) |
|
|
整数 |
4 |
(3) |
|
|
整数 |
8 |
(2), (3) |
|
|
整数 |
8 |
(2), (3) |
|
|
整数 |
(4) |
|
|
|
整数 |
(4) |
|
|
(7) |
浮動小数点数 |
2 |
(5) |
|
|
浮動小数点数 |
4 |
(5) |
|
|
浮動小数点数 |
8 |
(5) |
|
|
bytes |
||
|
|
bytes |
||
|
|
整数 |
(6) |
バージョン 3.3 で変更: 'n' および 'N' フォーマットのサポートが追加されました。
バージョン 3.6 で変更: 'e' フォーマットのサポートが追加されました。
注釈:
'?'変換コードは C99 で定義された_Bool型に対応します。その型が利用できない場合は、charで代用されます。標準モードでは常に1バイトで表現されます。変換コード
'q'および'Q'は、ネイティブモードではプラットフォームの C コンパイラが C のlong long型をサポートする場合、または Windows では__int64をサポートする場合にのみ利用できます。標準モードでは常に利用できます。非整数を整数の変換コードを使ってパックしようとすると、非整数が
__index__()メソッドを持っていた場合は、整数に変換するためにパックする前にそのメソッドが呼ばれます。バージョン 3.2 で変更: 非整数に対して
__index__()メソッドが使われるようになったのは 3.2 の新機能です。'n'および'N'変換コードは (デフォルトもしくはバイトオーダ文字'@'付きで選択される) native サイズ使用時のみ利用できます。standard サイズ使用時には、自身のアプリケーションに適する他の整数フォーマットを使うことができます。'f'、'd'および'e'変換コードについて、パックされた表現は IEEE 754 binary32 ('f'の場合) 、 binary64 ('d'の場合) 、またはbinary16('e'の場合) フォーマットが、プラットフォームにおける浮動小数点数のフォーマットに関係なく使われます。'P'フォーマット文字はネイティブバイトオーダでのみ利用可能です (デフォルトのネットワークバイトオーダに設定するか、'@'バイトオーダ指定文字を指定しなければなりません)。'='を指定した場合、ホスト計算機のバイトオーダに基づいてリトルエンディアンとビッグエンディアンのどちらを使うかを決めます。struct モジュールはこの設定をネイティブのオーダ設定として解釈しないので、'P'を使うことはできません。IEEE 754 の binary16 "半精度" 型は、 IEEE 754 standard の2008 年の改訂で導入されました。 半精度型は、符号 bit 、5 bit の指数部、 11 bit の精度 (明示的には 10 bit が保存される) を持ち、おおよそ
6.1e-05から6.5e+04までの数を完全な精度で表現できます。 この型は C コンパイラでは広くはサポートされていません: たいていのマシンでは、保存するのに unsigned short が使えますが、数学の演算には使えません。 詳しいことは Wikipedia の half-precision floating-point format のページを参照してください。
フォーマット文字の前に整数をつけ、繰り返し回数 (count) を指定することができます。例えば、フォーマット文字列 '4h' は 'hhhh' と全く同じ意味です。
フォーマット文字間の空白文字は無視されます; count とフォーマット文字の間にはスペースを入れてはいけません。
's' フォーマット文字での繰り返し回数 (count) は、他のフォーマット文字のような繰り返し回数ではなく、バイト長として解釈されます。例えば、'10s' は単一の 10 バイトの文字列を意味し、'10c' は 10 個の文字を意味します。繰り返し回数が指定されなかった場合は、デフォルト値の 1 とみなされます。パックでは、文字列はサイズに合うように切り詰められたり null バイトで埋められたりします。アンパックでは、返されるバイトオブジェクトのバイト数は、正確に指定した通りになります。特殊な場合として、'0s' は単一の空文字列を意味し、'0c' は 0 個の文字を意味します。
整数フォーマット ('b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q') のいずれかを使って値 x をパックするとき x がフォーマットの適切な値の範囲に無い場合、 struct.error が送出されます。
バージョン 3.1 で変更: 3.0 では、いくつかの整数フォーマットが適切な範囲にない値を覆い隠して、 struct.error の代わりに DeprecationWarning を送出していました。
フォーマット文字 'p' は "Pascal 文字列 (pascal string)" をコードします。Pascal 文字列は count で与えられる 固定長のバイト列 に収められた短い可変長の文字列です。このデータの先頭の 1 バイトには文字列の長さか255 のうち、小さい方の数が収められます。その後に文字列のバイトデータが続きます。 pack() に渡された Pascal 文字列の長さが長すぎた (count-1 よりも長い) 場合、先頭の count-1 バイトが書き込まれます。文字列が count-1 よりも短い場合、指定した count バイトに達するまでの残りの部分はヌルで埋められます。 unpack() では、フォーマット文字 'p' は指定された count バイトだけデータを読み込みますが、返される文字列は決して 255 文字を超えることはないので注意してください。
'?' フォーマット文字では、返り値は True または False です。パックするときには、引数オブジェクトの論理値としての値が使われます。 0 または 1 のネイティブや標準の真偽値表現でパックされ、アンパックされるときはゼロでない値は True になります。
7.1.2.3. 使用例¶
注釈
全ての例は、ビッグエンディアンのマシンで、ネイティブのバイトオーダ、サイズおよびアラインメントを仮定します。
基本的な例として、三つの整数をパック/アンパックします:
>>> 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
アンパックした結果のフィールドは、変数に割り当てるか 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)
アラインメントの要求を満たすために必要なパディングが異なるという理由により、フォーマット文字の順番がサイズの違いを生み出すことがあります:
>>> 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
以下のフォーマット 'llh0l' は、long 型が 4 バイトを境界としてそろえられていると仮定して、末端に 2 バイトをパディングします:
>>> pack('llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'
この例はネイティブのサイズとアラインメントが使われているときだけ思った通りに動きます。標準のサイズとアラインメントはアラインメントの設定ではいかなるアラインメントも行いません。
7.1.3. クラス¶
struct モジュールは次の型を定義します:
-
class
struct.Struct(format)¶ フォーマット文字列 format に従ってバイナリデータを読み書きする、新しい Struct オブジェクトを返します。 Struct オブジェクトを一度作ってからそのメソッドを使うと、フォーマット文字列のコンパイルが一度で済むので、
structモジュールの関数を同じフォーマットで何度も呼び出すよりも効率的です。コンパイルされた Struct オブジェクトは以下のメソッドと属性をサポートします:
-
pack_into(buffer, offset, v1, v2, ...)¶ pack_into()関数と同じ、コンパイルされたフォーマットを利用するメソッドです。
-
unpack_from(buffer, offset=0)¶ unpack_from()関数と同じ、コンパイルされたフォーマットを利用するメソッドです。 (buffer のバイト数 - offset は少なくともsize以上でなければなりません)。
-
iter_unpack(buffer)¶ iter_unpack()関数と同じ、コンパイルされたフォーマットを利用するメソッドです。 (buffer のバイト数はsizeの倍数でなければなりません)。バージョン 3.4 で追加.
-
format¶ この Struct オブジェクトを作成する時に利用されたフォーマット文字列です。
-
