高度なPython開発コース
チャプター
>
レベル
シリアライゼーションモジュール
Structモジュール
目的
struct モジュールを使って新しい農地の最終データ内訳を設定します。
道の突き当たりにはすでに建設され作物が植えられた新しい農地を管理するサービスステーションがあります。ここでは、すでに植えられた作物と農地の予想収穫量に関するデータを検査し処理します。他のレベルと同様に、シリアライズとデシリアライズを扱い、最後に struct モジュールを紹介します。
struct モジュールは一連のシリアライズ関数を提供し、データをバイナリ形式でパックします。ただし、これまで扱ってきた他のモジュールとは異なり、シリアライズ時とデシリアライズ時のデータ構造を細かく制御できるため、より汎用性があります。import struct を使用して、以下の関数にアクセスしデータ処理に使用します:
struct.calcsize(): 指定したフォーマット文字列が何バイトにパックされるかを判定します。引数は1つ(バイト数を確認したいフォーマット)。以下のフォーマットを使用します:- integer:
'i'で表され、整数値を表します - float:
'f'で表され、小数値を表します - double:
'd'で表され、float では不十分な高精度小数値を表します
- integer:
struct.pack(): データをバイナリ形式でシリアライズし、指定したフォーマットでパックします。引数は2つ以上で、最初がフォーマット、続くものがシリアライズしたい値です。フォーマットは先述のものを使用し、引数の数に合わせて指定します。struct.unpack(): パックされたバイナリデータをデシリアライズします。引数は2つで、1つ目がシリアライズ時と同じフォーマット、2つ目がシリアライズされたデータです。struct.iter_unpack():struct.unpack()と同様にバイナリデータをデシリアライズしますが、ループを用いて各データブロックを個別にイテレートします。struct.pack_into():struct.pack()の拡張版で、フォーマット、データを格納するバッファ、バッファ内の位置、パックするデータの4つの引数を取ります。struct.unpack_from():struct.unpack()の拡張版で、フォーマット、デシリアライズ元のバッファ、バッファ内の位置の3つの引数を取ります。データの特定部分をデシリアライズできます。
サービスステーションの光るXマークまで移動し、机に向かって立ちます。3つの変数 integer、float、double を作成します。これらを使って struct.calcsize() で各フォーマットのバイト数を確認します。integer には 'i'、float には 'f'、double には 'd' を引数として渡します。例: integer = struct.calcsize('i')。作成した3つの変数をあらかじめ用意された write() 関数に追加します。
金のXマークまで移動し、read() 関数を使って新農地のデータを取得します。データポイントおよびフォーマットを今後のためにメモします: Resources、Size、Estimate。メモを終えたら青いカーペット上の光るXマークまで移動し、blue_data という変数を作成します。
blue_data 変数には struct.pack() の戻り値を格納します。引数には先ほどメモしたフォーマットと値を指定します。フォーマットは単一の文字列として“パック”します。例えば整数フォーマットは 'i' ですが、整数が3つなら 'iii' とします。同様に整数、浮動小数点、倍精度小数を順に指定するなら 'ifd' とします。値は引数として個別に渡します。以下は例です:
data_1 = 8 # is an integer data_2 = 2.25 # is a float data_3 = 900.702938103 # is a double blue_data = struct.pack('ifd', data_1, data_2, data_3)
struct.pack() は柔軟性が高く、データのフォーマットを指定し複数のデータポイントを一度にシリアライズできます。先ほど読み取ったデータを上記の例をベースに追加し、display() 関数に blue_data を渡してパックされたデータを表示します。
青いカーペット上の暗いXマークまで移動し、ターミナルに向かいます。blue_unpack という変数を作成し、struct.unpack() の戻り値を格納します。引数にはデータをパックしたときと同じフォーマットと blue_data を指定します。struct.pack() と同様のフォーマット記述で、シリアライズとデシリアライズの構造を一致させます。write() 関数に blue_unpack を渡して、以前パックしたデータを確認します。
同じ場所で struct.iter_unpack() 関数も使用します。引数は struct.unpack() とまったく同じですが、for ループ内で使用してデータをイテレートできます。以下のように記述します:
for values in struct.iter_unpack(-insert value-, -insert value-): player.speak(values)
speak() 関数を使って値を表示します。struct.iter_unpack() の欠けている引数には、struct.unpack() と同じフォーマットとデータを指定します。これらは同じ関数のバリエーションです。
赤いカーペット上の金のXマークまで移動し、机に向かいます。read() 関数を使って作物の数量を確認します。各作物の数量とフォーマットをメモします。赤いカーペット上の光るXマークまで移動し、buffer というオブジェクトを作成して bytearray(16) を代入します。これはバイトを格納できるコレクションで、手動でデータを格納できるデータバンクのように機能します。引数 16 は buffer が保持できるバイト数です。
struct.pack_into() を使って buffer オブジェクトにデータを格納します。戻り値を受け取る変数は不要です。関数は直接 buffer に挿入します。先ほどメモした各値について関数を実行し、引数を指定します。
たとえば、最初の作物値ではフォーマット、バイト位置、数量が与えられます。1つ目の引数にフォーマット、2つ目にシリアライズ先のバッファ(この場合は buffer)、3つ目にバッファ内の位置、最後にシリアライズする値を指定します。
struct.pack_into('i', buffer, 0, 82)
先述の通り buffer オブジェクトは16バイトを持ちます。上記コードでは整数フォーマットが4バイトで位置0に挿入されます。つまり、位置0~3が値(この場合は82)で占有され、残りの12バイト(位置4~15)は空いています。先ほど読み取った作物データポイント(計3つ)について同様に pack_into を実行します。display() 関数に buffer を渡してシリアライズされたデータを表示します。
赤いカーペット上の暗いXマークまで移動し、ターミナルに向かいます。ここではデータをデシリアライズして内容を検証し、正しく格納されていることを確認します。3つの変数 lettuce、carrots、melons を作成し、それぞれのデータポイントを個別にアンパックします。各変数には struct.unpack_from() の戻り値を格納し、引数にはパック時にメモしたデータを使用します。1つ目にフォーマット、2つ目にアンパック元のバッファ buffer、3つ目にバッファ内の位置を指定します。例:
lettuce = struct.unpack_from('i', buffer, 0)
このデータは前述のパック例に対応しています。同様に残り2つの変数についても実行し、最後に lettuce、carrots、melons をあらかじめ用意された write() 関数に渡してレベルを完了させます。