Avancerad Pythonutvecklingskurs
Kapitel
>
Nivå

Serialiseringsmoduler
Struct-modul

Mål

Sätt upp slutgiltig datauppdelning för den nya åkermarken med hjälp av struct-modulen.

Längst bort på vägen finns en servicestation som ansvarar för den nya åkermarken som redan byggts och där grödorna redan är planterade. Här kommer vi att inspektera och bearbeta data för de planterade grödorna och den beräknade avkastningen från åkermarken. Precis som i tidigare nivåer i detta kapitel kommer vi att arbeta med att serialisera och deserialisera data, och introducera en sista modul vid namn struct-modulen.

Struct-modulen introducerar en serie serialiseringsfunktioner som paketerar data i binärt format. Till skillnad från de andra modulerna vi har arbetat med får du dock större kontroll över hur datan struktureras både vid serialisering och deserialisering, vilket gör den mer mångsidig än de andra modulerna. Använd import struct för att få åtkomst till följande funktioner som vi kommer att använda för att bearbeta datan:

  • struct.calcsize(): Bestämmer hur många byte en given formatsträng packar; den tar ett (1) argument, vilket är formatet du vill kontrollera storleken på i byte. De format vi kommer att använda är:
    • integer: representeras av 'i' och är formatet för data i heltal
    • float: representeras av 'f' och är formatet för data i decimaltal
    • double: representeras av 'd' och är formatet för mer komplexa decimaltal där float-formatet är otillräckligt
  • struct.pack(): Serialiserar data i binärt format, packat efter ett format du väljer. Den kan ta två (2) eller flera argument: det första är formatet du vill använda och de följande är de värden du vill serialisera. De format som används är de som beskrevs ovan, och du måste lägga till dem i motsvarande ordning som argumenten.
  • struct.unpack(): Avserialiserar packad binär data, tar två (2) argument: formatet som måste stämma överens med det som användes vid serialiseringen, och det packade dataobjektet.
  • struct.iter_unpack(): Avserialiserar packad binär data och fungerar på samma sätt som struct.unpack(), men itererar genom varje datablock individuellt med en loop.
  • struct.pack_into(): En avancerad version av struct.pack(), tar fyra (4) argument: formatet du vill använda, databufferten dit du vill skriva datan, positionen i bufferten där datan ska placeras, och slutligen värdet du packar.
  • struct.unpack_from(): En avancerad version av struct.unpack(), tar tre (3) argument: formatet du vill använda, databufferten du vill avpacka från, och slutligen läget i bufferten där du vill avpacka. Detta låter dig avpakera specifika delar av datan.

Gå till den ljusa X-markeringen i servicestationen och stå vid skrivbordet. Skapa tre (3) variabler med namnen: integer, float och double. Vi kommer att använda dem för att kontrollera storleken i byte för varje format med hjälp av funktionen struct.calcsize(). För variabeln integer använder du funktionen med 'i' som argument, för variabeln float med 'f' som argument och slutligen för variabeln double med 'd' som argument. Till exempel: integer = struct.calcsize('i'). Lägg till de tre (3) variablerna i den förskrivna funktionen write().

Gå till den gyllene X-markeringen och använd funktionen read() för att samla in data om den nya åkermarken. Anteckna datapunkterna och deras format för framtida användning, nämligen: Resources, Size och Estimate. När du har antecknat detta, gå till den ljusa X-markeringen på den blå mattan och skapa en variabel som heter blue_data.

I variabeln blue_data ska du lagra värdet från funktionen struct.pack(), där du anger de format och de värden du antecknade tidigare som argument. När du skriver formatsträngen måste du packa formattypeparna till en enda enhet. Till exempel är integer-formatet betecknat 'i', och om du lägger till tre heltal formaterar du det som 'iii'. På samma sätt, om du lägger till ett heltal, ett flyttal och ett dubbelprecisionsflyttal, skrivs det 'ifd'. När du lägger till själva värdena anger du dem som separat argument. Här är ett övergripande exempel:

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() ger mycket flexibilitet, så att du kan ange hur du vill formatera datan och serialisera flera datapunkter samtidigt efter eget gottfinnande. Lägg till de tidigare inlästa värdena med exemplet ovan som grund. Använd funktionen display() med blue_data som argument för att visa den packade datan.

Gå till den mörka X-markeringen på den blå mattan och ställ dig vid terminalen. Skapa en variabel som heter blue_unpack och lagra värdet från funktionen struct.unpack(), där du anger samma format som användes vid packningen och variabeln blue_data som argument. Formatsträngen skrivs på samma sätt som i struct.pack(), för att du ska kunna deserialisera datan på samma sätt som du serialiserade den. Använd funktionen write() med blue_unpack som argument för att verifiera den data du tidigare packade.

På samma ställe kommer vi också att använda funktionen struct.iter_unpack(). Den tar exakt samma argument som struct.unpack(), men är utformad som en for-loop, vilket låter oss iterera över datan istället för att helt enkelt skriva ut allt på en gång. Funktionen kodas som följer:

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

Vi kommer att använda funktionen speak() för att visa värdena. För de saknade argumenten i funktionen struct.iter_unpack(), använd samma som tidigare användes med struct.unpack(), eftersom det är variationer av samma funktion ur användningssynpunkt.

Gå till den gyllene X-markeringen på den röda mattan och stå vid skrivbordet. Använd funktionen read() för att granska grödornas kvantiteter. Anteckna alla kvantiteter och formatet för varje gröda. Gå sedan till den ljusa X-markeringen på den röda mattan och skapa ett objekt som heter buffer samt tilldela det värdet bytearray(16). Detta är en samling byte som vi kan adressera innan vi fyller den; för våra syften fungerar det som en databank där du manuellt kan lagra data. Siffran 16 som argument är antalet byte du kan lagra i objektet buffer.

Använd funktionen struct.pack_into() för att fylla objektet buffer du skapade. Det är inte nödvändigt att skapa en variabel för att lagra funktionens returvärde, eftersom funktionen själv kommer att infoga värdena direkt i objektet buffer. Vi kommer att använda funktionen för varje värde vi tidigare antecknat och ange dess argument därefter.

Till exempel, för det första grödvärdet som anges kommer du att få dess format, dess byteposition och dess kvantitet. Ange formatet som det första argumentet och bufferten buffer som det andra argumentet. För det tredje argumentet anger du den position du vill skriva in värdet i buffer; formatet avgör hur många byte som används, så se till att packa in data på lediga positioner. Slutligen anger du det värde du vill serialisera och packa in i objektet buffer.

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

Objektet buffer har 16 byte som tidigare nämnts. I koden ovan har integer-formatet 4 byte och skrivs in på position 0. Det innebär att när datan är inlagd i buffer återstår bara 12 byte som är oallokerade, med positionerna 03 upptagna av det inskrivna värdet, i detta fall 82. Gör detta för alla de gröd­data du tidigare läst in och antecknat; det är totalt tre (3) datapunkter. Använd funktionen display() med buffer som argument för att visa den serialiserade datan.

Gå till den mörka X-markeringen på den röda mattan och ställ dig vid terminalen. Här kommer vi att deserialisera datan för att verifiera innehållet och säkerställa korrekt lagring. Skapa tre variabler med namnen: lettuce, carrots och melons; vi kommer att avpacka data för varje datapunkt individuellt. För varje variabel lagrar du värdet från struct.unpack_from() och anger som argument samma data som du noterade för packningen. Det första argumentet är formatet, det andra är objektet buffer, och slutligen anger du positionen i buffer som du vill avpacka från. Till exempel:

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

Denna data motsvarar exemplet på packning ovan som nu avpackas. Gör på samma sätt för de två övriga variablerna och sätt in lettuce, carrots och melons i den förskrivna funktionen write() för att slutföra nivån.

Kodbok