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, ...)

フォーマット文字列 fmt に従い値 v1, v2, ... をパックして、文字列で返します。引数は指定したフォーマットが要求する型と正確に一致していなければなりません。

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

フォーマット文字列 fmt に従い値 v1, v2, ... をパックして文字列にし、書き込み可能な buffer のオフセット offset 位置より書き込みます。オフセットは省略出来ません。

バージョン 2.5 で追加.

struct.unpack(fmt, string)

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

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

バッファ bufferoffset の位置から、書式化文字列 fmt に従ってアンパックします。結果は要素が1つでもタプルとして返されます。buffer は少なくとも書式が要求するデータサイズを持っていなくてはなりません (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

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

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)

f

float

float

4

(4)

d

double

float

8

(4)

s

char[]

string

p

char[]

string

P

void *

integer

(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 個の文字列です。count の指定がない場合のデフォルトは 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 整数型が使われます。

'?' フォーマット文字では、返り値は True または False です。パックするときには、引数オブジェクトの論理値としての値が使われます。 0 または 1 のネイティブや標準の真偽値表現でパックされ、アンパックされるときはゼロでない値は 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'

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

参考

array モジュール

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

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 (とそれによる文字列) のサイズを計算したものです。