Coding for KidsCoding for Kids
クリエイティブレベル挑戦教師ガイド
機能に投票
上級Python開発コース
チャプター
>
レベル

シリアル化モジュール
構造体モジュール

目的

structモジュールを使用して、新しい農地の最終データ内訳を設定します。

道の終わりには、既に建設された農地と植えられた作物を管理するサービスステーションがあります。ここでは、既に植えられた作物のデータと農地の予測出力を検査および処理します。この章の他のレベルと同様に、データのシリアライズとデシリアライズを扱い、最後のモジュールとして structモジュールを導入します。

structモジュールは、データをバイナリ形式でパックする一連のシリアライズ関数を提供します。他のモジュールとは異なり、シリアライズ時および後のデシリアライズ時にデータの構造をより詳細に制御できるため、非常に柔軟です。以下の関数を使用してデータを処理するために、import struct を使用してください:

  • struct.calcsize(): 指定されたフォーマット文字列が何バイトでパックされるかを決定します。引数として確認したいフォーマットを一つ (1) 受け取ります。使用するフォーマットは以下の通りです:
    • integer: 'i' で表され、整数で表現されるデータのフォーマットです。
    • float: 'f' で表され、小数点を含む数値を表現するデータのフォーマットです。
    • double: 'd' で表され、floatフォーマットでは不十分なより複雑な小数点数を表現するデータのフォーマットです。
  • struct.pack(): 指定されたフォーマットでデータをバイナリにシリアライズします。2つ以上の引数を取ります。最初の引数は使用するフォーマット、その後にシリアライズしたい値を渡します。フォーマットは前述の通りで、追加する引数の数に応じて対応するフォーマットを加える必要があります。
  • struct.unpack(): バイナリ形式にパックされたデータをデシリアライズします。2つの引数を取り、最初がシリアライズ時と同じ形式であるフォーマット、次がシリアライズされたデータです。
  • struct.iter_unpack(): パックされたバイナリデータをデシリアライズします。struct.unpack() と同じ引数を取りますが、ループを使用して各データブロックを個別に反復処理できるようにします。
  • struct.pack_into(): struct.pack() の拡張版で、4つの引数を取ります。フォーマット、データを挿入するバッファ、バッファ内の配置位置、最後にパックしたいデータを指定します。
  • struct.unpack_from(): struct.unpack() の拡張版で、3つの引数を取ります。フォーマット、データを取り出すバッファ、そしてバッファからデータを取り出す位置を指定します。これにより、データの特定部分のみをデシリアライズすることができます。

サービスステーションのライトXマークへ歩いて向かい、机の前に立って、integerfloatdouble という3つの変数を作成してください。これらを使用して、struct.calcsize() 関数を用い、それぞれのフォーマットのバイトサイズを検証します。integer 変数には引数として 'i' を渡し、float 変数には 'f'、最後に double 変数には 'd' を渡してください。例えば: integer = struct.calcsize('i') 。3つの変数を既に用意された write() 関数に追加してください。

ゴールドのXマークへ歩いて向かい、read() 関数を使用して新しい農地のデータを収集し、将来使用するためにデータポイントとそのフォーマット、すなわち ResourcesSizeEstimate に注意を払ってください。記録したら、ライトのXマークへ歩き、青いカーペットの上で blue_data という変数を作成してください。

blue_data 変数には、先に記録したフォーマットと値を引数として渡し、struct.pack() 関数の値を格納してください。フォーマットを書く際には、フォーマットタイプを一つのユニットに「パック」する必要があります。例として、整数フォーマットは先に説明した 'i' ですが、もし整数が3つある場合は、'iii' とします。同様に、整数、float、doubleを追加する場合は、'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)

不足している struct.iter_unpack() 関数の引数には、struct.unpack() で以前使用したものと同じ引数を追加してください。これらは同じ関数のバリエーションであり、使い方は同じです。

レッドカーペット上のゴールドXマークへ歩いて向かい、机の前に立って、read() 関数を使い作物の数量を確認してください。各作物の数量とそのフォーマットに注意を払い記録してください。ライトのXマークへ歩き、赤いカーペットの上で buffer というオブジェクトを作成し、bytearray(16) の値を格納してください。これは、データを手動で格納できるバイトの集合であり、データバンクのように機能します。引数として指定された 16 は、buffer オブジェクトに格納できるバイトの長さです。

struct.pack_into() 関数を使用して、作成した buffer オブジェクトにデータを埋め込みます。関数の値を格納する変数を作成する必要はなく、関数自体が直接 buffer オブジェクトに値を挿入します。先に記録した全ての作物のデータポイントに対して、この関数を使用して各引数を埋め込んでください。

例えば、提供された最初の作物の値については、そのフォーマット、バイトの位置、数量が与えられます。最初の引数としてフォーマット、次にシリアライズするバイトの配置先である buffer 、3番目の引数として buffer 内の値を追加したい位置、最後にシリアライズしてパックする値を追加します。

struct.pack_into('i', buffer, 0, 82)

上記のコードから、buffer オブジェクトは先に述べた通り16バイトを持ち、整数フォーマットは4バイトで位置0に挿入されます。つまり、値が挿入されると buffer 内では位置0~3に82が格納され、残りは12バイトが未使用となります。同様の手順で、記録した全ての作物データ(合計3つ)に対して実施してください。display() 関数を使用し、buffer を引数として渡してシリアライズされたデータを表示してください。

レッドカーペット上のダークXマークへ歩いて向かい、端末に向かって、今回はデシリアライズを行い、正しくデータが格納されているかを確認します。lettucecarrotsmelons という3つの変数を作成し、各データポイントを個別にアンパックしてください。各変数には、struct.unpack_from() の値を格納し、引数として先に記録したデータと同じ引数を使用してください。最初の引数にフォーマット、次にアンパックする場所である buffer オブジェクト、最後にアンパックする buffer 内の位置を指定します。例えば:

lettuce = struct.unpack_from('i', buffer, 0)

これは先のパックの例に対応してアンパックしたものです。同様に、他の2つの変数についても実施し、lettucecarrotsmelons を既に用意された write() 関数に挿入してレベルを完了してください。

コードブック