Pokročilý kurz vývoje v Pythonu
Kapitola
>
Úroveň

Serializační moduly
Modul struktur

Cíl

Nastavte konečné rozčlenění dat pro novou zemědělskou půdu pomocí modulu struct.

Na konci cesty se nachází servisní stanice, která spravuje novou zemědělskou půdu, jež již byla vystavěna a na které byly zasety plodiny. Zde budeme kontrolovat a zpracovávat data o již zasetých plodinách a odhadovaném výnosu zemědělské půdy. Stejně jako v předchozích úrovních této kapitoly budeme pracovat s serializací a deserializací dat a představíme jeden poslední modul nazvaný struct.

Modul struct přináší řadu funkcí pro serializaci, které balí data do binárního formátu. Na rozdíl od ostatních modulů, se kterými jsme dosud pracovali, máte větší kontrolu nad tím, jak data strukturujeme při jejich serializaci i pozdější deserializaci, což činí tento modul všestrannější. Pro přístup k následujícím funkcím, které použijeme ke zpracování dat, použijte import struct:

  • struct.calcsize(): Určuje, kolik bajtů zabírá daný formátovací řetězec; bere jeden (1) argument, kterým je formát, jehož velikost v bajtech chcete ověřit. Formáty, které budeme používat, jsou:
    • integer: reprezentovaný jako 'i', formát pro data vyjádřená celými čísly
    • float: reprezentovaný jako 'f', formát pro data vyjádřená desetinnými čísly
    • double: reprezentovaný jako 'd', formát pro data vyžadující složitější desetinná čísla, kde formát float nestačí.
  • struct.pack(): Serializuje data do binárního formátu dle zvoleného formátu. Může přijmout dva (2) nebo více argumentů: formát, který chcete použít, a hodnoty, které chcete serializovat. Formáty jsou ty, které jsme si již popsali, a je třeba je přidat v počtu odpovídajícím počtu předaných hodnot.
  • struct.unpack(): Deserializuje zabalená binární data; bere dva (2) argumenty: formát, se kterým se musí shodovat formát původní serializace, a druhý argument jsou serializovaná data.
  • struct.iter_unpack(): Deserializuje zabalená binární data; funguje stejně jako struct.unpack(), ale prochází každý blok dat jednotlivě pomocí cyklu.
  • struct.pack_into(): Rozšířená verze struct.pack(); bere čtyři (4) argumenty: formát, datový buffer, do kterého chcete data vložit, pozici v bufferu, kterou mají data zabrat, a nakonec samotná data, která balíte.
  • struct.unpack_from(): Rozšířená verze struct.unpack(); bere tři (3) argumenty: formát, datový buffer, ze kterého chcete data rozbalit, a nakonec pozici v bufferu, ze které se mají data rozbalit. Tímto způsobem můžete rozbalovat konkrétní části dat.

Jděte ke světlé značce X na servisní stanici a postavte se čelem k pultu, vytvořte tři (3) proměnné pojmenované: integer, float a double. Použijeme je k ověření velikosti (v bajtech) každého formátu pomocí funkce struct.calcsize(). Pro proměnnou integer použijte funkci s argumentem 'i', pro proměnnou float s argumentem 'f' a nakonec pro proměnnou double s argumentem 'd'. Například: integer = struct.calcsize('i'). Přidejte tyto tři proměnné do předpřipravené funkce write().

Jděte ke zlaté značce X a použijte funkci read(), abyste získali data o nové zemědělské půdě, a poznamenejte si datové body a jejich formáty pro budoucí použití, konkrétně: Resources, Size a Estimate. Poté, co si to poznamenáte, jděte ke světlé značce X na modrém koberci a vytvořte proměnnou blue_data.

Do proměnné blue_data uložte hodnotu funkce struct.pack(), přičemž argumenty budou formát a hodnoty, které jste si dříve poznamenali. Při zadávání formátu musíte „zabalit“ jednotlivé typy formátu do jednoho řetězce. Například formát pro celé číslo je označen 'i', a pokud přidáváte tři celočíselné hodnoty, napíšete 'iii'. Stejně tak pokud přidáváte celočíselnou hodnotu, desetinnou a dvojnásobnou, napíšete 'ifd'. Hodnoty pak předáváte jednotlivě jako argumenty. Zde je obecný příklad:

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)

Funkce struct.pack() nabízí velkou flexibilitu, umožňuje nastavit požadovaný formát dat a serializovat více datových bodů najednou podle vašeho uvážení. Přidejte dříve načtená data s využitím výše uvedeného příkladu jako základ. Pro zobrazení zbalených dat použijte funkci display() s argumentem blue_data.

Jděte ke tmavé značce X na modrém koberci a postavte se k terminálu, vytvořte proměnnou blue_unpack a uložte do ní hodnotu funkce struct.unpack(), přičemž argumenty budou stejný formát použitý při zpracování dat a proměnná blue_data. Formát se zapisuje stejným způsobem jako u funkce struct.pack(), aby bylo možné data deserializovat v pořadí, v jakém byla původně serializována. Pro ověření dříve zapsaných dat použijte funkci write() s argumentem blue_unpack.

Na stejném místě použijeme také funkci struct.iter_unpack(), která bere stejné argumenty jako struct.unpack(), ale je zapsána jako for smyčka, což nám umožní data postupně zpracovávat místo jejich jednoho výpisu. Funkce je napsána následovně:

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

Budeme používat funkci speak() k zobrazení hodnot; do chybějících argumentů funkce struct.iter_unpack() vložte stejné, které jste použili u struct.unpack(), protože se jedná o varianty téže funkce z hlediska použití.

Jděte ke zlaté značce X na červeném koberci a postavte se ke stolku, použijte funkci read() ke kontrole množství plodin. Poznamenejte si všechna množství a formát pro každou plodinu. Poté jděte ke světlé značce X na červeném koberci a vytvořte objekt buffer s hodnotou bytearray(16). Jedná se o kolekci bajtů, ke které můžeme před naplněním přistupovat – pro naše účely funguje jako datová banka, kde lze ručně uložit data. Číslo 16 jako argument udává délku (počet bajtů), který lze v objektu buffer uložit.

Použijte funkci struct.pack_into() k naplnění dříve vytvořeného objektu buffer. Není třeba vytvářet proměnnou pro uložení návratové hodnoty funkce, protože funkce sama vloží hodnoty přímo do objektu buffer. Pro každý dříve zaznamenaný údaj použijte tuto funkci a vyplňte její argumenty odpovídajícími hodnotami.

Například pro první hodnotu plodiny dostanete informaci o jejím formátu, pozici v bajtech a množství. Do prvního argumentu vložte formát, do druhého argumentu uveďte cílový buffer, v našem případě buffer. Ve třetím argumentu nastavte pozici, na kterou se má hodnota v objektu buffer uložit – formát totiž určuje, kolik bajtů bude využito, takže je třeba balit data na neobsazené pozice. Nakonec přidejte hodnotu, kterou chcete serializovat a vložit do objektu buffer.

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

Objekt buffer má, jak již bylo řečeno, 16 bajtů. V uvedeném kódu má formát integer 4 bajty a je vložen na pozici 0. To znamená, že po vložení této hodnoty zůstává v bufferu ještě 12 neobsazených bajtů (pozice 03 zabírá hodnota 82). Proveďte totéž u všech tří (3) dříve načtených datových bodů plodin. Pro zobrazení serializovaných dat použijte funkci display() s argumentem buffer.

Jděte ke tmavé značce X na červeném koberci a postavte se k terminálu; zde budeme data deserializovat, abychom ověřili jejich obsah a správné uložení. Vytvořte tři proměnné pojmenované lettuce, carrots a melons; data každého z nich rozbalíme samostatně. Pro každou proměnnou uložte hodnotu funkce struct.unpack_from() a jako argumenty použijte stejná data, která jste zjistili při balení. Jako první argument zadejte formát, druhý argument bude objekt buffer (místo rozbalování) a nakonec pozici v bufferu, ze které chcete data rozbalit. Například:

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

Tato data odpovídají dříve uvedenému příkladu balení, nyní je rozbalujeme; totéž proveďte i pro zbývající dvě proměnné a vložte lettuce, carrots a melons do předpřipravené funkce write(), čímž dokončíte úroveň.

Kniha Kódu