Python structモジュールは、Cのstructデータ型にアクセスしたり操作したりするためのシンプルなPythonicインターフェースを提供するために使用されます。
このモジュールはPythonの値をCの構造体に変換することができ、その逆も可能です。
このモジュールはPythonの値をCの構造体に変換したり、その逆を行うことができます。Cの構造体はPythonのバイトオブジェクトとして使用されますが、これはCにはオブジェクトというものがなく、バイトサイズのデータ構造しかないからです。
Python structモジュールのメソッド
このモジュールではC言語の構造体を扱うので、このモジュールが提供する関数のいくつかを見てみましょう。
struct.pack()
これは要素をPythonのバイト文字列(バイトオブジェクト)にパックするために使用されます。
Format: struct.pack(v1,v2,v3,v4,v5,v6,v6)
Pythonのバイト文字列に要素をパックします。pack(format, v1, v2, …)
v1
v2
, …は、バイトオブジェクトにパックされる値です。 これらはC構造体のフィールド値を表しています。 n
のフィールドを持つC構造は、正確にn
の値を持たなければならないので、引数はフォーマットが要求する値と正確に一致しなければなりません。 これは、Cコードで使用されるようなバイト文字列のデータ型を指定する必要があるために必要です。 以下の表は、format
の最も一般的な値の一覧です。 データ型を指定するには、値ごとに1つのフォーマットが必要です。
フォーマット | C Datatype | Pythonタイプ |
char | a string of 長さ1 | |
? |
_Bool | _bool |
h |
short | integer |
l |
long | 整数 |
i |
int | 整数 |
f |
float | |
d |
double | float |
s |
char | string |
いくつかの例を使って理解していきましょう。
以下のスニペットは、pack()
を使用して、3つの整数1、2、3をバイトオブジェクトに格納しています。 私のマシンでは整数のサイズは4バイトなので、4バイトのブロックが3つ見えますが、これはC言語では3つの整数に相当します。
import struct# We pack 3 integers, so 'iii' is requiredvariable = struct.pack('iii', 1, 2, 3)print(type(variable), variable)variable_2 = struct.pack('iic', 1, 2, b'A')print('\n', variable_2)
出力
<class 'bytes'> b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00'b'\x01\x00\x00\x00\x02\x00\x00\x00A'
適切な型が渡されない場合は、Pythonのstructモジュールによって例外struct.error
が発生します。
import struct# Error!! Incorrect datatype assignmentvariable = struct.pack('ccc', 1, 2, 3)print(type(variable), variable)
出力
struct.error: char format requires a bytes object of length 1
struct.unpack()
Python structモジュールのこの関数は、パックされた値を適切なフォーマットにしたがって元の表現にアンパックします。
Format: struct.unpack(format, string)
これは string
format
というフォーマット指定子に従って展開します。
これは struct.pack()
unpack()
を使って渡されたpythonの値を返してみましょう。
import structbyte_str = b'\x01\x00\x00\x00\x02\x00\x00\x00A'# Using the same format specifier as before, since# we want to get Python values for the same byte-stringtuple_vals = struct.unpack('iic', byte_str)print(tuple_vals)
出力
(1, 2, b'A')
確かに、ご覧の通りです。 pack()
unpack()
の両方に同じフォーマット指定子を使用すれば、このタプルから古いPythonの値をパックすることができます。
struct.calcsize()
この関数は、データの型を取得してサイズを計算するために、与えられたフォーマット指定子を使用して、構造体のString表現の合計サイズを返します。
Format: struct.calcsize(fmt)
import structprint('C Integer Size in Bytes:', struct.calcsize('i'))print('Size of 3 characters in Bytes:', struct.calcsize('ccc'))
Output
C Integer Size in Bytes: 4Size of 3 characters in Bytes: 3
struct.pack_into()
この関数は、ctypes
モジュールで利用可能なPythonの文字列バッファに値をパックするために使用されます。
Format: struct.pack_into(fmt, buffer, offset, v1, v2, …)
ここで、fmt
buffer
は、指定されたパックされた値を格納する文字列バッファです。
これは値を返さず、buffer
の文字列に値を格納します。
import struct import ctypes # We will create a string buffer having a size# equal to that of a struct with 'iic' values.buf_size = struct.calcsize('iic') # Create the string bufferbuff = ctypes.create_string_buffer(buf_size) # struct.pack() returns the packed data struct.pack_into('iic', buff, 0, 1, 2, b'A')print(buff)# Display the contents of the bufferprint(buff)
出力
<ctypes.c_char_Array_9 object at 0x7f4bccef1040>b'\x01\x00\x00\x00\x02\x00\x00\x00A'
つまり、バッファ文字列にパックされた値を取得しています。
struct.unpack_from()
unpack()
と同様に、バッファ文字列から値を取り出すための対応策があります。
Format: struct.unpack_from(fmt, buffer, offset)
これは struct.unpack()
と同様に、値のタプルを返します。
import struct import ctypes # We will create a string buffer having a size# equal to that of a struct with 'iic' values.buf_size = struct.calcsize('iic') # Create the string bufferbuff = ctypes.create_string_buffer(buf_size) # struct.pack() returns the packed data struct.pack_into('iic', buff, 0, 1, 2, b'A')print(struct.unpack_from('iic', buff, 0))
出力
(1, 2, b'A')
まとめ
本記事では、Pythonのstructモジュールを使ってC型構造体オブジェクトを扱う方法を学びました。