Coding for KidsCoding for Kids
Creatieve LevelsUitdagingenLerarengids
Stem op functies
Gevorderde Python-ontwikkelingscursus
Hoofdstuk
>
Niveau

Serialisatiemodules
Struct-module

Doelstelling

Stel de definitieve gegevensverdeling in voor de nieuwe boerderij met behulp van de struct-module.

Aan het einde van de weg bevindt zich een service station dat de nieuwe boerderij beheert, welke al is gebouwd en waar al gewassen zijn geplant. Hier gaan we de gegevens inspecteren en verwerken voor de al ingeplante gewassen en de verwachte opbrengst van de boerderij. Net als bij de andere niveaus in dit hoofdstuk werken we met het serialiseren en deserialiseren van data, en introduceren we een laatste module genaamd de struct-module.

De struct-module introduceert een reeks serialisatiefuncties die data in binair formaat verpakt. In tegenstelling tot de andere modules waarmee we hebben gewerkt, heb je meer controle over hoe we de data kunnen structureren, zowel wanneer het wordt geserialiseerd als later bij het deserialiseren, waardoor het veelzijdiger is dan andere modules. Gebruik import struct om toegang te krijgen tot de volgende functies die we zullen gebruiken om de data te verwerken:

  • struct.calcsize(): Bepaalt hoeveel bytes een gegeven formaatstring verpakt. Het neemt één (1) argument, namelijk het formaat waarvan je de bytegrootte wilt controleren. De formaten die we zullen gebruiken zijn:
    • integer: weergegeven als 'i' is het formaat voor data in gehele getallen.
    • float: weergegeven als 'f' is het formaat voor data in decimale getallen.
    • double: weergegeven als 'd' is het formaat voor data in complexere decimale getallen waarbij het float-formaat onvoldoende is.
  • struct.pack(): Serialiseert data in binair formaat, verpakt in een door jou gekozen formaat. Je kunt hier twee (2) of meer argumenten aan meegeven, namelijk het formaat dat je wilt gebruiken en de waarden die je wilt serialiseren. De formaten zijn de eerder beschreven en je moet deze toevoegen overeenkomstig het aantal meegegeven argumenten.
  • struct.unpack(): Deserialiseert verpakte binaire data. Het neemt twee (2) argumenten, het formaat waarmee de data vergeleken moet worden (gelijk aan het formaat waarin het geserialiseerd is) en de data die geserialiseerd is.
  • struct.iter_unpack(): Deserialiseert verpakte binaire data, werkt op dezelfde manier als struct.unpack() maar doorloopt elk datablock afzonderlijk met behulp van een lus.
  • struct.pack_into(): Een geavanceerde versie van struct.pack(), neemt vier (4) argumenten: het formaat dat je wilt gebruiken, de databuffer waarin je de data wilt plaatsen, de positie in de buffer waar de data moet komen, en tenslotte de data die je verpakt.
  • struct.unpack_from(): Een geavanceerde versie van struct.unpack(), neemt drie (3) argumenten: het formaat dat je wilt gebruiken, de databuffer waarvan je wil uitpakken, en tenslotte de locatie in de buffer waarvan je de data wilt uitpakken. Hiermee kun je specifieke segmenten van de data uitpakken.

Loop naar het licht X-symbool in het service station en ga naar de balie, maak drie (3) variabelen aan met de namen: integer, float en double. We zullen deze gebruiken om de grootte in bytes van elk formaat te verifiëren met de functie struct.calcsize(). Voor de variabele integer gebruik je de functie met 'i' als argument, voor de variabele float de functie met 'f' als argument en voor de variabele double de functie met 'd' als argument. Bijvoorbeeld: integer = struct.calcsize('i'). Voeg de drie (3) variabelen toe aan de vooraf geschreven write() functie.

Loop naar het gouden X-symbool en gebruik de read() functie om data te verzamelen over de nieuwe boerderij. Noteer de gegevenspunten en het formaat voor toekomstig gebruik, namelijk: Resources, Size en Estimate. Nadat je deze gegevens hebt genoteerd, loop je naar het licht X-symbool over het blauwe tapijt en maak je een variabele aan met de naam blue_data.

Bewaar in de variabele blue_data de waarde van de struct.pack() functie, waarbij je als argumenten het formaat en de waarden gebruikt die je eerder hebt genoteerd. Bij het schrijven van het formaat moet je de formaten samenvoegen tot één enkele string. Bijvoorbeeld, het integer-formaat wordt aangeduid met 'i' zoals eerder beschreven. Als je drie integers toevoegt, schrijf je dit als 'iii'. Evenzo, als je een integer, een float en een double toevoegt, schrijf je dit als 'ifd'. Voeg de data vervolgens afzonderlijk als argumenten toe. Hieronder een algemeen voorbeeld:

data_1 = 8 # is een integer data_2 = 2.25 # is een float data_3 = 900.702938103 # is een double blue_data = struct.pack('ifd', data_1, data_2, data_3)

De functie struct.pack() biedt veel flexibiliteit, waardoor je kunt bepalen hoe je de data wilt formatteren en meerdere gegevenspunten tegelijk kunt serialiseren, naar eigen inzicht. Voeg de eerder gelezen gegevens toe met het bovenstaande voorbeeld als basis. Gebruik de display() functie met blue_data als argument om de verpakte data weer te geven.

Loop naar het donkere X-symbool over het blauwe tapijt en ga naar de terminal. Maak een variabele aan met de naam blue_unpack en sla de waarde op van de struct.unpack() functie, waarbij je dezelfde opmaak gebruikt als die waarmee je de data gepakt hebt en de variabele blue_data als argument geeft. Het formaat wordt op dezelfde manier geschreven als bij de struct.pack() functie, zodat je de data op dezelfde manier kunt deserialiseren als waarin deze oorspronkelijk geserialiseerd werd. Gebruik de write() functie met blue_unpack als argument om de eerder verpakte data te verifiëren.

Op dezelfde locatie gebruiken we ook de functie struct.iter_unpack(). Deze neemt precies dezelfde argumenten als struct.unpack(), maar wordt nu gebruikt in een for-lus. Dit stelt ons in staat om door de data te itereren in plaats van alles in één keer weer te geven. De functie wordt als volgt gecodeerd:

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

We zullen de speak() functie gebruiken om de waarden weer te geven. Voeg voor de ontbrekende argumenten in de struct.iter_unpack() functie dezelfde toe als eerder gebruikt bij struct.unpack(), aangezien dit variaties zijn van dezelfde functie, qua gebruik.

Loop naar het gouden X-symbool over het rode tapijt en ga naar de balie. Gebruik de read() functie om de hoeveelheden van de gewassen te bekijken. Noteer alle hoeveelheden en het formaat voor elk gewas. Loop naar het licht X-symbool over het rode tapijt en maak een object aan met de naam buffer, en ken de waarde bytearray(16) toe. Dit is een verzameling bytes die we kunnen adresseren voordat we deze vullen; voor onze doeleinden werkt het als een databank waar je handmatig data in kunt opslaan. Het getal 16 als argument geeft aan hoeveel bytes er opgeslagen kunnen worden in het buffer object.

Gebruik de functie struct.pack_into() om het aangemaakte buffer object te vullen. Het is niet nodig een variabele te maken om de waarde van de functie op te slaan, aangezien de functie de waarden direct in het buffer object plaatst. We gaan de functie gebruiken voor elk van de eerder genoteerde waarden en vullen daarbij de argumenten met de bijbehorende gegevens.

Bijvoorbeeld, voor de eerste opgegeven gewaswaarde krijg je het formaat, de bytepositie en de hoeveelheid. Voeg het formaat toe als eerste argument, de locatie waarin je de bytes wilt serialiseren (in dit geval buffer) als tweede argument. Stel als derde argument de positie in het buffer object in waar je de waarde wilt plaatsen. Het formaat bepaalt het aantal bytes dat wordt gebruikt, dus wees voorzichtig om data die nog niet is bezet, in te pakken. Voeg tenslotte de waarde toe die je wilt serialiseren en in het buffer object wilt plaatsen.

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

Het buffer object heeft 16 bytes zoals eerder vermeld. In de bovenstaande code gebruikt het integer-formaat 4 bytes en wordt ingevoegd op positie 0. Dit betekent dat zodra de data in het buffer object is ingevoegd, er nog slechts 12 bytes onbezet zijn, waarbij de posities 0-3 worden ingenomen door de opgegeven waarde, in dit geval 82. Doe dit voor alle eerder genoteerde gewasgegevens; er zijn er drie (3) in totaal. Gebruik de functie display() en geef buffer mee om de geserialiseerde data te tonen.

Loop naar het donkere X-symbool over het rode tapijt en ga naar de terminal. Hier zullen we de data deserialiseren om de inhoud te verifiëren en een correcte opslag te garanderen. Maak drie variabelen aan met de namen: lettuce, carrots en melons. We zullen de data van elk gegeven afzonderlijk uitpakken. Sla voor elke variabele de waarde op van struct.unpack_from() en geef als argumenten dezelfde data die je eerder hebt genoteerd voor het inpakken. Gebruik als eerste argument het formaat, voeg als tweede argument het buffer object toe als de locatie om uit te pakken en geef als derde argument de positie in het buffer object op waarvan je wilt uitpakken. Bijvoorbeeld:

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

Deze data komt overeen met het eerder ingepakte voorbeeld dat nu wordt uitpakken. Doe hetzelfde voor de twee andere variabelen en voeg lettuce, carrots en melons toe aan de vooraf geschreven write() functie om het niveau te voltooien.

Codeboek