Avancerad Pythonutvecklingskurs
Kapitel
>
Nivå
Serialiseringsmoduler
Struct-modul
Mål
Ställ in den slutgiltiga datauppdelningen för den nya gården med hjälp av struct-modulen.
I slutet av vägen finns en servicestation som administrerar den nya gården som redan är byggd och där grödorna redan har planterats. Här ska vi inspektera och bearbeta data för de redan planterade grödorna samt den förväntade produktionen från gården. Precis som med andra nivåer i detta kapitel kommer vi att arbeta med serialisering och deserialisering av data, och introducera en sista modul som heter struct-modulen.
struct-modulen introducerar en rad serialiseringsfunktioner som packar data i binärt format. Till skillnad från de andra modulerna vi arbetat med, ger den dig större kontroll över hur vi kan strukturera datan både när den är serialiserad och senare deserialiserad, vilket gör den mer mångsidig än andra moduler. Använd import struct för att få tillgång till följande funktioner som vi kommer att använda för att bearbeta datan:
struct.calcsize(): Bestämmer hur många bytes som krävs för att packa en given formatsträng. Den tar ett (1) argument, vilket är det format du vill verifiera byte-storleken på. De format vi kommer att använda är:- integer: representeras som
'i'och är formatet för data som representeras som heltal - float: representeras som
'f'och är formatet för data som representeras med decimaltal - double: representeras som
'd'och är formatet för data som representeras med mer komplexa decimaltal, där float-formatet är otillräckligt.
- integer: representeras som
struct.pack(): Serialiserar data till binärt format, packat i ett format som du väljer. Funktionen kan ta två (2) eller fler argument, där det första är det format du vill använda och de efterföljande är de värden du vill serialisera. Formaten är de som tidigare beskrevs och du måste lägga till dem i enlighet med antalet argument du skickar.struct.unpack(): Deserialiserar packad binär data, tar två (2) argument: formatet som datan ska jämföras med det format den serialiserades i, och det andra är den serialiserade datan.struct.iter_unpack(): Deserialiserar packad binär data, fungerar på samma sätt somstruct.unpack()men itererar genom varje datablock individuellt med hjälp av en loop.struct.pack_into(): En avancerad version avstruct.pack(). Tar fyra (4) argument som är det format du vill använda, databufferten du vill skriva in datan i, positionen i bufferten där datan ska placeras, och slutligen själva datan som ska packas.struct.unpack_from(): En avancerad version avstruct.unpack(). Tar tre (3) argument: det format du vill använda, databufferten du vill packa upp, och slutligen positionen i bufferten från vilken du vill packa upp. Detta tillåter dig att packa upp specifika delar av datan.
Gå till det ljusblå X-märket vid servicestationen och stå vid disken, skapa tre (3) variabler med namnen: integer, float och double. Vi ska använda dessa för att verifiera storleken i bytes 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 använder du funktionen med 'f' som argument och slutligen, för variabeln double använder du funktionen med 'd' som argument. Exempel: integer = struct.calcsize('i'). Lägg till de tre (3) variablerna i den förskrivna funktionen write().
Gå till det gyllene X-märket och använd funktionen read() för att samla in data om den nya gården. Notera datapunkterna och formaten för framtida bruk, nämligen: Resources, Size och Estimate. När du har gjort dina anteckningar, gå till det ljusblå X-märket på den blå mattan och skapa en variabel med namnet blue_data.
Med variabeln blue_data ska du lagra värdet av funktionen struct.pack(), där du som argument anger formatet och de värden du noterade tidigare. När du skriver formatet måste du "packa" formattyperna till en enhet. Exempelvis, om du vill lägga till tre heltalsdata, skriver du formatsträngen som 'iii' eftersom heltalsformatet representeras som 'i', som tidigare specificerats. På samma sätt, om du vill lägga till ett heltal, ett decimaltal och ett double-värde, skulle formatsträngen vara 'ifd'. När du anger datan ska de placeras individuellt som argument. Här är ett övergripande exempel:
data_1 = 8 # är ett heltal data_2 = 2.25 # är ett decimaltal data_3 = 900.702938103 # är ett double-värde blue_data = struct.pack('ifd', data_1, data_2, data_3)
Funktionen struct.pack() ger stor flexibilitet, eftersom den låter dig bestämma hur du vill formatera datan samt serialisera flera datapunkter samtidigt, efter eget gottfinnande. Lägg till den tidigare insamlade datan med exemplet ovan som bas. Använd funktionen display() med blue_data som argument för att visa den packade datan.
Gå till det mörka X-märket på den blå mattan och stå vid terminalen. Skapa en variabel med namnet blue_unpack och lagra värdet av funktionen struct.unpack() där du anger samma format som användes för att packa datan samt variabeln blue_data som argument. Formatet skrivs på samma sätt som i funktionen struct.pack(), så att du kan deserialisera datan på samma sätt som du först serialiserade den. Använd funktionen write() med blue_unpack som argument för att verifiera att datan du packade tidigare är korrekt.
På samma plats ska vi även använda funktionen struct.iter_unpack(). Den tar exakt samma argument som struct.unpack(), men nu är den formaterad som en for-loop, vilket gör att vi kan iterera över datan istället för att bara skriva ut allt på en gång. Funktionen kodas enligt följande:
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 med struct.unpack() eftersom de är varianter av samma funktion, både i användning och syntax.
Gå till det gyllene X-märket på den röda mattan och stå vid disken. Använd funktionen read() för att granska mängderna av grödorna. Notera alla kvantiteter och formatet för varje gröda. Gå sedan till det ljusblå X-märket på den röda mattan och skapa ett objekt med namnet buffer, och ge det värdet bytearray(16). Detta är en samling bytes som vi kan adressera innan vi fyller i det; för vårt syfte fungerar det som en databas där du kan lagra datan manuellt. Numret 16 som argument anger hur många bytes du kan lagra i buffer-objektet.
Använd funktionen struct.pack_into() för att fylla buffer-objektet du skapade. Det är inte nödvändigt att skapa en separat variabel för att lagra värdet av funktionen, då funktionen direkt sätter in värdena i buffer-objektet. Vi kommer att använda denna funktion för varje värde du tidigare noterade och fylla i dess argument.
Till exempel, för det första grödovärdet du fick, kommer du att få det specificerade formatet, positionen i bytes och kvantiteten. Ange formatet som första argument, platsen där du vill serialisera bytesen (i detta fall buffer) som andra argument. För det tredje argumentet anger du positionen där du vill lägga in värdet i buffer; formatet bestämmer hur många bytes som används, så var noga med att inte skriva över data som redan finns. Lägg slutligen till värdet du vill serialisera och packa in i buffer-objektet.
struct.pack_into('i', buffer, 0, 82)
buffer-objektet har 16 bytes som tidigare nämnts. I koden ovan har heltalsformatet 4 bytes och sätts in på position 0. Detta innebär att när datan har satts in i buffer finns det endast 12 bytes kvar obeskattade, där positionerna 0-3 är upptagna med det angivna värdet, i detta fall 82. Gör detta för alla tidigare noterade grödodatapunkter, det finns totalt tre (3). Använd funktionen display() med buffer som argument för att visa den serialiserade datan.
Gå till det mörka X-märket på den röda mattan och stå vid terminalen. Här ska vi deserialisera datan för att verifiera innehållet och säkerställa att det lagrats korrekt. Skapa tre variabler med namnen: lettuce, carrots och melons. Vi ska packa upp datan för varje datapunkt individuellt. För varje variabel lagrar du värdet av funktionen struct.unpack_from() och anger som argument samma data som du noterade när du packade in datan. För det första argumentet anger du formatet, för det andra skickar du buffer-objektet (platsen att packa upp ifrån) och slutligen positionen i buffer från vilken du vill packa upp. Exempel:
lettuce = struct.unpack_from('i', buffer, 0)
Denna data motsvarar exemplet för packning som packas upp, gör på samma sätt för de två andra variablerna och använd lettuce, carrots och melons som argument i den förskrivna funktionen write() för att slutföra nivån.