7.3. struct — 文字列データをパックされたバイナリデータとして解釈する

このモジュールは、 Python の値と Python 上で文字列データとして表される C の構造体データとの間の変換を実現します。このモジュールは特に、ファイルに保存されたり、ネットワーク接続を経由したバイナリデータを扱うときに使われます。このモジュールでは、C 構造体のレイアウトおよび Python の値との間で行いたい変換をコンパクトに表現するために、 フォーマット文字列 を使います。

注釈

デフォルトでは、与えられた C の構造体をパックする際に、関連する C データ型を適切にアラインメント(alignment)するために数バイトのパディングを行うことがあります。この挙動が選択されたのは、パックされた構造体のバイト表現を対応する C 構造体のメモリレイアウトに正確に対応させるためです。プラットフォーム独立のデータフォーマットを扱ったり、隠れたパディングを排除したりするには、サイズ及びアラインメントとして native の代わりに standard を使うようにします: 詳しくは バイトオーダ, サイズ, アラインメント を参照して下さい。

7.3.1. 関数と例外

このモジュールは以下の例外と関数を定義しています:

exception struct.error

様々な状況で送出された例外です; 引数は何が問題かを記述する文字列です。

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

v1, v2, ... が与えられたフォーマットで含まれる文字列データを返します。引数は指定したフォーマットが要求する型と正確に一致していなければなりません。

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

v1, v2, ... を与えられたフォーマットに従ってパックし、そのバイト列を書き込み可能な bufferoffset を先頭に書き込みます。 offset が省略できないことに注意してください。

バージョン 2.5 で追加.

struct.unpack(fmt, string)

(おそらく pack(fmt, ...) でパックされた) 文字列データを与えられた書式に従ってアンパックします。値が一つしかない場合を含め、結果はタプルで返されます。文字列データにはフォーマットが要求するだけのデータが正確に含まれていなければなりません (len(string)calcsize(fmt) と一致しなければなりません)。

struct.unpack_from(fmt, buffer[, offset=0])

buffer を与えられたフォーマットでアンパックします。値が一つしかない場合を含め、結果はタプルで返されます。 buffer には最低でも format に要求されるサイズのデータが必要です。 (len(buffer[offset:])calcsize(fmt) 以上でなければなりません)。

バージョン 2.5 で追加.

struct.calcsize(fmt)

与えられたフォーマットに対応する構造体のサイズ (すなわち文字列データのサイズ) を返します。

7.3.2. フォーマット文字列

フォーマット文字列はデータをパックしたりアンパックしたりするときの期待されるレイアウトを指定するためのメカニズムです。文字列はパック/アンパックされるデータの型を指定する フォーマット文字 から組み立てられます。さらに、 バイトオーダ, サイズ, アラインメント を制御するための特殊文字もあります。

7.3.2.1. バイトオーダ, サイズ, アラインメント

デフォルトでは、C での型はマシンのネイティブ (native) の形式およびバイトオーダ (byte order) で表され、適切にアラインメント (alignment) するために、必要に応じて数バイトのパディングを行ってスキップします (これは C コンパイラが用いるルールに従います)。

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

文字 バイトオーダ サイズ アラインメント
@ ネイティブ 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 式で決定されます。ネイティブのサイズおよびアラインメントはネイティブのバイトオーダと同時に使われます。

標準サイズはフォーマット文字だけで決まります。 フォーマット文字 の表を参照して下さい。

'@''=' の違いに注意してください: 両方ともネイティブのバイトオーダですが、後者のバイトサイズとアラインメントは標準のものに合わせてあります。

'!' 表記法はネットワークバイトオーダがビッグエンディアンかリトルエンディアンか忘れちゃったという熱意に乏しい人向けに用意されています。

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

注意:

  1. パディングは構造体のメンバの並びの中にだけ自動で追加されます。最初や最後にパディングが追加されることはありません。
  2. ネイティブでないサイズおよびアラインメントが使われる場合にはパディングは行われません。 (たとえば ‘<’, ‘>’, ‘=’, ‘!’ を使った場合です。)
  3. 特定の型によるアラインメント要求に従うように構造体の末端をそろえるには、繰り返し回数をゼロにした特定の型でフォーマットを終端します。 を参照して下さい。

7.3.2.2. フォーマット文字

フォーマット文字 (format character) は以下の意味を持っています; C と Python の間の変換では、値は正確に以下に指定された型でなくてはなりません: 「標準のサイズ」列は standard サイズ使用時にパックされた値が何バイトかを示します。つまり、フォーマット文字列が '<', '>', '!', '=' のいずれかで始まっている場合のものです。native サイズ使用時にはパックされた値の大きさはプラットフォーム依存です。

フォーマット C での型 Python 型 標準のサイズ 備考
x

パディングバイト

値なし

   
c char 長さ 1 の文字列 1  
b signed char 整数型 (integer) 1 (3)
B unsigned char 整数型 1 (3)
? _Bool 真偽値型(bool) 1 (1)
h short 整数型 2 (3)
H unsigned short 整数型 2 (3)
i int 整数型 4 (3)
I unsigned int 整数型 4 (3)
l long 整数型 4 (3)
L unsigned long 整数型 4 (3)
q long long 整数型 8 (2), (3)
Q unsigned long long 整数型 8 (2), (3)
f float 浮動小数点型 4 (4)
d double 浮動小数点型 8 (4)
s char[] 文字列    
p char[] 文字列    
P void * 整数型   (5), (3)

注意事項:

  1. '?' 変換コードは C99 で定義された _Bool 型に対応します。その型が利用できない場合は、 char で代用されます。標準モードでは常に1バイトで表現されます。

    バージョン 2.6 で追加.

  2. 変換コード 'q' および 'Q' は、ネイティブモードではプラットフォームの C コンパイラが C の long long 型をサポートする場合、または Windows では __int64 をサポートする場合にのみ利用できます。標準モードでは常に利用できます。

    バージョン 2.2 で追加.

  3. 整数変換コードで非整数をパックしようとするとき、その非整数が __index__() メソッドを持っていると、パッキングの前に、そのメソッドが変数を整数に変換するために呼び出されます。 __index__() メソッドが存在しないか、 __index__() メソッドの呼び出しが TypeError を送出したら、次に __int__() メソッドが試されます。しかし、 __int__() の使用は非推奨で、 DeprecationWarning を送出します。

    バージョン 2.7 で変更: 非整数への __index__() メソッド の使用は 2.7 で追加されました。

    バージョン 2.7 で変更: バージョン 2.7 以前では、すべての整数変換コードが変換に __int__() メソッドを使うわけではなく、浮動小数点の引数にのみ DeprecationWarning が送出されていました。

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

  5. 'P' フォーマット文字はネイティブバイトオーダでのみ利用可能です (デフォルトのネットワークバイトオーダに設定するか、 '@' バイトオーダ指定文字を指定しなければなりません)。 '=' を指定した場合、ホスト計算機のバイトオーダに基づいてリトルエンディアンとビッグエンディアンのどちらを使うかを決めます。 struct モジュールはこの設定をネイティブのオーダ設定として解釈しないので、 'P' を使うことはできません。

フォーマット文字の前に整数をつけ、繰り返し回数 (count) を指定することができます。例えば、フォーマット文字列 '4h''hhhh' と全く同じ意味です。

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

フォーマット文字 's' では、count は文字列のサイズとして扱われます。他のフォーマット文字のように繰り返し回数ではありません; 例えば、 '10c' が 10 個のキャラクタを表すのに対して、 '10s' は 10 バイトの長さを持った 1 個の文字列です。文字列をパックする際には、指定した長さにフィットするように、必要に応じて切り詰められたりヌル文字で穴埋めされたりします。また特殊なケースとして、('0c' が 0 個のキャラクタを表すのに対して) '0s' は 1 個の空文字列を意味します。

フォーマット文字 'p' は “Pascal 文字列 (pascal string)” をコードします。Pascal 文字列は count で与えられる 固定長のバイト列 に収められた短い可変長の文字列です。このデータの先頭の 1 バイトには文字列の長さか255 のうち、小さい方の数が収められます。その後に文字列のバイトデータが続きます。 pack() に渡された Pascal 文字列の長さが長すぎた (count-1 よりも長い) 場合、先頭の count-1 バイトが書き込まれます。文字列が count-1 よりも短い場合、指定した count バイトに達するまでの残りの部分はヌルで埋められます。 unpack() では、フォーマット文字 'p' は指定された count バイトだけデータを読み込みますが、返される文字列は決して 255 文字を超えることはないので注意してください。

フォーマット文字 'P' では、返される値は Python 整数型または long 整数型で、これはポインタの値を Python での整数にキャストする際に、値を保持するために必要なサイズに依存します。 NULL ポインタは常に Python 整数型の 0 になります。ポインタ型のサイズを持った値をパックする際には、Python 整数型および long 整数型オブジェクトを使うことができます。例えば、 Alpha および Merced プロセッサは 64 bit のポインタ値を使いますが、これはポインタを保持するために Python long 整数型が使われることを意味します; 32 bit ポインタを使う他のプラットフォームでは Python 整数型が使われます。

フォーマット文字 '?' では、返される値は TrueFalse のどちらかです。パック時にはオブジェクトの真偽値が利用されます。 0 か 1 のネイティブもしくは標準のbool表現がパックされます。そしてアンパック時には非ゼロの値は True になります。

7.3.2.3. 例

注釈

全ての例は、ビッグエンディアンのマシンで、ネイティブのバイトオーダ、サイズおよびアラインメントを仮定します。

基本的な例として、三つの整数をパック/アンパックします:

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

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

>>> record = '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='raymond   ', serialnum=4658, school=264, gradelevel=8)

アラインメントの要求を満たすために必要なパディングが異なるという理由により、フォーマット文字の順番がサイズの違いを生み出すことがあります:

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

以下のフォーマット 'llh0l' は、 long 型が 4 バイトを境界としてそろえられていると仮定して、末端に 2 バイトをパディングします:

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

この例はネイティブのサイズとアラインメントが使われているときだけ思った通りに動きます。標準のサイズとアラインメントはアラインメントの設定ではいかなるアラインメントも行いません。

参考

Module array
一様なデータ型からなるバイナリ記録データのパック
Module xdrlib
XDR データのパックおよびアンパック。

7.3.3. クラス

struct モジュールは次の型を定義します:

class struct.Struct(format)

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

バージョン 2.5 で追加.

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

pack(v1, v2, ...)

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

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

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

unpack(string)

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

unpack_from(buffer[, offset=0])

unpack_from() 関数と同じ、コンパイルされたフォーマットを利用するメソッドです。 (len(buffer[offset:])self.size 以上でなければなりません)。

format

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

size

format に対応する struct (とそれによる文字列) のサイズを計算したものです。