Coding for KidsCoding for Kids
Creative LevelsChallengesTeacher's Guide
Vote for features
Advanced Python Development Course
Chapter
>
Level

Serialization-modules
Struct Module

Objective

Set up the final data breakdown for the new farmland using the struct module.

At the end of the road there is a service station which administers the new farmland that is already built and crops already planted. Here we’ll be inspecting and processing the data for the crops already planted and the projected output of the farmland. Like with other levels in this chapter we’ll be working with serializing and deserializing data, introducing one final module named the struct module.

The struct module introduces a series of serialization functions that packs data in binary format, unlike the other modules we’ve worked with however, you have greater control of how we can structure the data both when it’s serialized and later deserialized, making it more versatile than other modules. Use import struct in order to access the following functions which we’ll be using to process the data:

  • struct.calcsize(): Determines how many bytes is packed a given format string, it takes one (1) argument being the format you’d like to verify it’s byte size. The format’s we’ll be using are:
    • integer: represented as 'i' is the format for data represented in whole numbers
    • float: represented as 'f' is the format for data represented in decimal numbers
    • double: represented as 'd' is the format for data represented in more complex decimal numbers where the float format is insufficient.
  • struct.pack(): Serializes data in binary, packed in a format of your choosing. You can takes two (2) or more arguments, that being the format you wish to use and the values you would like to serialize. The formats are the ones previously outlined and you must add them corresponding to the amount of arguments you add.
  • struct.unpack(): Deserializes packed binary data, takes two (2) arguments, the format in which it needs to be comparable to the format it was serialized in, and the second is the data that was serialized.
  • struct.iter_unpack(): Deserializes packed binary data, works the same way as struct.unpack() but iterates through each data block individually through the use of a loop.
  • struct.pack_into(): An advanced version of struct.pack() , takes four (4) arguments which would be the format you would like to use, the data buffer you’d like to put the data into, the position in the buffer you’d like the data to occupy, and finally the data you’re packing.
  • struct.unpack_from(): An advanced version of struct.unpack() , takes three (3) arguments : the format you would like to use, the data buffer you’d like to unpack and lastly the location in the buffer you would like to unpack. This allows you to unpack specific portions of the data.

Walk to the light X mark in the service station and face the desk, create three (3) variables named: integer , float and double. We’ll use these to verify the size in bytes of each format by using the struct.calcsize() function. For the integer variable use the function with 'i' as an argument, for the float variable use the function with 'f' as an argument and lastly with the double variable use the function with 'd' as an argument. For example: integer = struct.calcsize('i') . Add the three (3) variables to pre-written write() function.

Walk to gold X mark and use the read() function in order to collect data on the new farmland, make note of the data points and format for future use namely: Resources , Size and Estimate . Once you make note of this walk to the light X mark over the blue carpet and create a variable named blue_data .

With the blue_data variable store the value of the struct.pack() function, setting as arguments the format and values you made note of previously. When writing the format, you must “pack” the format types into one single unit. For example, the integer format is labeled 'i' as previously detailed, if you are adding three integer data types, you add them as 'iii' . In the same vein, if you’re adding an integer a float and a double, it would be written 'ifd' . When adding the data, you place them individually as arguments. Here is an overall example:

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)

The struct.pack() function allows a lot of flexibility, allowing you to set how you would like to format the data and allowing you to serialize multiple data points at once, at your discretion. Add the previously read data using the example above as a base. Use the display() function with blue_data as an argument to view the packed data.

Walk to the dark X mark over the blue carpet and face the terminal, create a variable named blue_unpack and store the value of the struct.unpack() function, adding the same format used to pack the data and the blue_data variable as arguments. The format is written in the same manner as the struct.pack() function, that way you may deserialize data in the same fashion as you first serialized it. Use the write() function with blue_unpack as an argument to verify the data you previously packed.

At the same location we will also use the struct.iter_unpack() function, it takes the exact same arguments as struct.unpack() however now it’s formatted as a for loop, this allows us to iterate the data as opposed to simply writing it all out. The function is coded as follows:

for values in struct.iter_unpack(-insert value-, -insert value-): player.speak(values)

We’ll be using the speak() function to display the values, for the missing arguments in the struct.iter_unpack() function, add the same ones previously used with struct.unpack() as these are variations of the same function, usage wise.

Walk to the gold X mark over red carpet and face the desk use the read() function to review the crop quantities. Make note of all the quantities and the format for each crop. Walk to the light X mark over red carpet and create an object named buffer, and add the value of bytearray(16) . This is a collection of bytes that we can address before populating it, for our purposes it works like a data bank where you can store the data manually. The number 16 as an argument is the length of how many bytes you can store in the buffer object.

Use the struct.pack_into() function to populate the buffer object you created. No need to create a variable to store the value of the function as the function itself will insert the values directly into the buffer object. We’re going to use the function for each of the values we previously noted and populate their arguments with it.

For example, for the first crop value provided, you’ll be provided it’s format , it’s bytes position and it’s quantity. Add the format for the first argument, the location you wish to serialize the bytes to which in this case is buffer . For the third argument set the position you’d like to add the value inside the buffer , the format determines the bytes used up so be use to pack data that wasn’t previously occupied. Lastly add the value you would like to serialize and pack into the buffer object.

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

The buffer object has 16 bytes as previously stated, in the code provided above, the integer format has 4 bytes and is inserted at position 0 . This means that once the data is inserted into the buffer there are only 12 bytes left inside buffer unoccupied with position 0-3 being occupied by the value provided, in this case being 82. Do this for all the crop data points previously read and noted, there are three (3) total. Use the display() function and add buffer to display the serialized data.

Walk to the dark X mark over the red carpet and face the terminal, here we’ll be deserializing the data to verify the contents to ensure proper storage. Create three variables named: lettuce , carrots and melons , we’ll unpack the data of each data points individually. For each of the variable store the value of struct.unpack_from() and set as arguments using the same data you noted to pack the data. For the first argument set the format, the second add the buffer object which is the location to unpack from and lastly add the position in the buffer which you would like to unpack from. For example:

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

This data corresponds to the previous packing example being unpacked, do the same for the two other variable and insert lettuce , carrots and melons into the pre-written write() function in order to complete the level.

Code book