Avanceret Python-udviklingskursus
Kapitel
>
Niveau

Serialiseringsmoduler
Strukturmodul

Mål

Opsæt den endelige dataopdeling for den nye landbrugsjord ved hjælp af struct-modulet.

Ved vejs ende er der en servicestation, som administrerer den nye landbrugsjord, der allerede er opført, og de afgrøder, der allerede er plantet. Her vil vi inspicere og behandle data for de allerede plantede afgrøder og det forventede udbytte af landbrugsjorden. Som med de andre niveauer i dette kapitel arbejder vi med at serialisere og deserialisere data og introducerer et sidste modul, der hedder struct-modulet.

Struct-modulet introducerer en række serialiseringsfunktioner, der pakker data i binært format. I modsætning til de andre moduler, vi har arbejdet med, har du dog større kontrol over, hvordan vi kan strukturere dataene både under serialisering og senere deserialisering, hvilket gør det mere alsidigt end de andre moduler. Brug import struct for at få adgang til følgende funktioner, som vi vil bruge til at bearbejde dataene:

  • struct.calcsize(): Bestemmer hvor mange bytes, der pakkes af en given formatstreng. Den tager ét (1) argument, nemlig formatet, du vil verificere størrelsen af i bytes. De formater, vi vil bruge, er:
    • integer: repræsenteret som 'i' er formatet for tal i hele tal
    • float: repræsenteret som 'f' er formatet for tal i decimaler
    • double: repræsenteret som 'd' er formatet for mere komplekse decimaltal, hvor float-formatet er utilstrækkeligt.
  • struct.pack(): Serialiserer data i binært format med et format, du vælger. Den kan tage to (2) eller flere argumenter, nemlig det format, du ønsker at bruge, og de værdier, du vil serialisere. Formaterne er dem, der er beskrevet ovenfor, og du skal tilføje dem svarende til antallet af argumenter, du angiver.
  • struct.unpack(): Deserialiserer pakkede binære data. Den tager to (2) argumenter: formatet, som skal matche det format, dataene blev serialiseret med, og dataene, der blev serialiseret.
  • struct.iter_unpack(): Deserialiserer pakkede binære data og fungerer på samme måde som struct.unpack(), men itererer gennem hver datapakke individuelt ved hjælp af en løkke.
  • struct.pack_into(): En avanceret version af struct.pack(). Den tager fire (4) argumenter: formatet, du ønsker at bruge, databufferen, du vil indsætte dataene i, positionen i bufferet, som dataene skal optage, og endelig de data, du pakker.
  • struct.unpack_from(): En avanceret version af struct.unpack(). Den tager tre (3) argumenter: formatet, du ønsker at bruge, databufferen, du vil pakke ud fra, og endelig den position i bufferet, du vil pakke ud fra. Dette giver dig mulighed for at udpakke specifikke dele af dataene.

Gå hen til det lyse X-mærke i servicestationen og vend dig mod skrivebordet. Opret tre (3) variabler med navne: integer, float og double. Vi vil bruge disse til at verificere størrelsen i bytes for hvert format ved hjælp af funktionen struct.calcsize(). For variablen integer bruger du funktionen med 'i' som argument, for variablen float bruger du funktionen med 'f' som argument, og til sidst bruger du for variablen double funktionen med 'd' som argument. For eksempel: integer = struct.calcsize('i'). Tilføj de tre (3) variabler til den forudskrevne write()-funktion.

Gå hen til det gyldne X-mærke og brug read()-funktionen for at indsamle data om den nye landbrugsjord. Notér datapunkterne og formaterne til fremtidig brug, nemlig: Ressourcer, Størrelse og Estimat. Når du har noteret dette, går du til det lyse X-mærke over det blå tæppe og opretter en variabel ved navn blue_data.

I variablen blue_data gemmer du værdien fra struct.pack()-funktionen og angiver som argumenter det format og de værdier, du tidligere har noteret. Når du skriver formatet, skal du “pakke” formaterne ind i en enkelt enhed. For eksempel er integer-formatet mærket 'i', som tidligere nævnt; hvis du tilføjer tre heltal, angiver du 'iii'. På samme måde, hvis du tilføjer et integer, et float og et double, skrives det 'ifd'. Når du tilføjer dataene, placerer du dem enkeltvis som argumenter. Her er et samlet eksempel:

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)

Funktionen struct.pack() giver stor fleksibilitet, da du kan vælge, hvordan du vil formatere dataene, og du kan serialisere flere datapunkter på én gang efter eget skøn. Tilføj de tidligere indlæste data med eksemplet ovenfor som udgangspunkt. Brug funktionen display() med blue_data som argument for at vise de pakkede data.

Gå hen til det mørke X-mærke over det blå tæppe og vend dig mod terminalen. Opret en variabel ved navn blue_unpack og gem værdien fra struct.unpack()-funktionen ved at angive det samme format, som blev brugt til at pakke dataene, og variablen blue_data som argumenter. Formatet skrives på samme måde som i struct.pack(), så du kan deserialisere dataene på samme måde, som du først serialiserede dem. Brug write()-funktionen med blue_unpack som argument for at bekræfte de data, du tidligere pakkede.

På samme sted vil vi også bruge funktionen struct.iter_unpack(). Den tager de samme argumenter som struct.unpack(), men er nu formateret som en for-løkke, hvilket giver os mulighed for at iterere over dataene i stedet for blot at skrive dem ud. Funktionen kodes som følger:

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

Vi vil bruge speak()-funktionen til at vise værdierne. For de manglende argumenter i struct.iter_unpack()-funktionen tilføjer du de samme, som du tidligere brugte med struct.unpack(), da det er variationer af den samme funktion, brugsmæssigt.

Gå hen til det gyldne X-mærke over det røde tæppe og vend dig mod skrivebordet. Brug read()-funktionen til at gennemse afgrødekvantiteterne. Notér alle kvantiteterne og formatet for hver afgrøde. Gå til det lyse X-mærke over det røde tæppe og opret et objekt ved navn buffer med værdien bytearray(16). Dette er en samling af bytes, som vi kan adressere, inden vi befolker den; til vores formål fungerer det som en databank, hvor du manuelt kan gemme data. Tallet 16 angiver, hvor mange bytes du kan gemme i objektet buffer.

Brug funktionen struct.pack_into() til at befolke objektet buffer, du oprettede. Der er ikke behov for at oprette en variabel til at gemme funktionens værdi, da funktionen selv indsætter værdierne direkte i objektet buffer. Vi vil bruge funktionen til hver af de værdier, vi tidligere noterede, og udfylde deres argumenter med dem.

For eksempel får du for den første afgrødeangivelse formatet, dets byteposition og dets mængde. Tilføj formatet som det første argument, placeringen, hvor du vil serialisere bytes, hvilket i dette tilfælde er buffer. For det tredje argument angiver du den position i buffer, hvor du vil indsætte værdien – formatet bestemmer, hvor mange bytes der bruges, så sørg for at pakke data, der ikke er optaget i forvejen. Til sidst tilføjer du den værdi, du ønsker at serialisere og pakke ind i objektet buffer.

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

Objektet buffer har 16 bytes som tidligere nævnt. I koden ovenfor har integer-formatet 4 bytes og indsættes ved position 0. Det betyder, at når dataene er indsat i buffer, er der kun 12 bytes tilbage i buffer uden indhold, hvor positionerne 0-3 er optaget af den angivne værdi, i dette tilfælde 82. Gør dette for alle de afgrødedatapunkter, du tidligere læste og noterede; der er i alt tre (3). Brug funktionen display() og tilføj buffer for at vise de serialiserede data.

Gå hen til det mørke X-mærke over det røde tæppe og vend dig mod terminalen. Her vil vi deserialisere dataene for at verificere indholdet og sikre korrekt lagring. Opret tre variabler med navne: lettuce, carrots og melons. Vi pakker dataene fra hvert datapunkt individuelt ud. For hver variabel gemmer du værdien fra struct.unpack_from() og angiver som argumenter de samme data, du noterede, da du pakkede dem. Til det første argument angiver du formatet, til det andet tilføjer du objektet buffer, som er den buffer, du vil udpakke fra, og til sidst tilføjer du den position i buffer, du vil udpakke fra. For eksempel:

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

Disse data svarer til det tidligere paknings-eksempel, der nu pakkes ud. Gør det samme for de to andre variabler, og indsæt lettuce, carrots og melons i den forudskrevne write()-funktion for at fuldføre niveauet.

Kodebog