Pokročilý kurz vývoje v Pythonu
Kapitola
>
Úroveň
Serializační moduly
Modul struktury
Cíl
Nastavte konečné členění dat pro nové zemědělské pole pomocí modulu struct.
Na konci cesty se nachází servisní stanice, která spravuje novou usedlost, jež již byla postavena a plodiny již byly zasazeny. Zde budeme inspektovat a zpracovávat data o již zasazených plodinách a očekávaném výstupu usedlosti. Stejně jako v ostatních úrovních této kapitoly budeme pracovat se serializací a deserializací dat a představíme jeden poslední modul s názvem struct.
Modul struct představuje řadu funkcí pro serializaci, které data balí do binárního formátu. Na rozdíl od ostatních modulů, se kterými jsme pracovali, vám poskytuje větší kontrolu nad tím, jak lze strukturovat data při serializaci i následné deserializaci, čímž je univerzálnější. Pro přístup k následujícím funkcím, které budeme používat ke zpracování dat, použijte příkaz import struct:
struct.calcsize(): Určuje, kolik bajtů zabírá daný formátový řetězec. Přijímá jeden (1) argument, kterým je formát, jehož velikost v bajtech chcete ověřit. Formáty, které budeme používat, jsou:- integer: Reprezentován jako
'i'; formát pro data ve formě celých čísel. - float: Reprezentován jako
'f'; formát pro data ve formě desetinných čísel. - double: Reprezentován jako
'd'; formát pro data ve formě složitějších desetinných čísel, kdy formát float nestačí.
- integer: Reprezentován jako
struct.pack(): Serializuje data do binárního formátu podle vámi zvoleného formátu. Může přijímat dva (2) nebo více argumentů – formát, který chcete použít, a hodnoty, které chcete serializovat. Použitými formáty jsou ty, které byly dříve uvedeny, a musí být přidány podle počtu argumentů.struct.unpack(): Deserializuje zabalená binární data. Přijímá dva (2) argumenty: formát, podle kterého mají data být porovnána s formátem, ve kterém byla serializována, a data samotná.struct.iter_unpack(): Deserializuje zabalená binární data, funguje stejně jakostruct.unpack(), ale iteruje přes každý datový blok jednotlivě pomocí cyklu.struct.pack_into(): Pokročilá verze funkcestruct.pack(), přijímá čtyři (4) argumenty: formát, který chcete použít, datový buffer, do kterého chcete data vložit, pozici v bufferu, kterou data zaujmou, a nakonec data, která balíte.struct.unpack_from(): Pokročilá verze funkcestruct.unpack(), přijímá tři (3) argumenty: formát, který chcete použít, datový buffer, ze kterého chcete data rozbalit, a nakonec pozici v bufferu, odkud data chcete rozbalit. To vám umožní rozbalit konkrétní části dat.
Vydejte se ke značce X s bílým světlem ve servisní stanici a postavte se ke stolu, vytvořte tři (3) proměnné s názvy: integer, float a double. Tyto proměnné použijeme k ověření velikosti každého formátu v bajtech pomocí funkce struct.calcsize(). Pro proměnnou integer použijte tuto 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 (3) proměnné do předem připravené funkce write().
Vydejte se ke zlaté značce X a použijte funkci read(), abyste sesbírali data o nové usedlosti. Poznamenejte si datové body a formát pro budoucí použití, konkrétně: Resources, Size a Estimate. Jakmile si je zaznamenáte, vydejte se ke značce X s bílým světlem přes modrý koberec a vytvořte proměnnou s názvem blue_data.
Do proměnné blue_data uložte hodnotu funkce struct.pack(), přičemž jako argumenty nastavíte formát a hodnoty, které jste si předtím poznamenali. Při zápisu formátu musíte „zabalit“ formátovací typy do jediné jednotky. Například, pokud je formát celého čísla označen jako 'i' a chcete přidat tři celá čísla, zapíšete to jako 'iii'. Podobně, pokud chcete přidat celé číslo, desetinné číslo a double, zapíšete to jako 'ifd'. Hodnoty pak přidá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 vám nastavit, jak chcete data formátovat, a zároveň umožňuje serializovat více datových bodů najednou, dle vašeho uvážení. Přidejte dříve načtená data podle výše uvedeného příkladu jako základ. Použijte funkci display() s argumentem blue_data pro zobrazení zabalených dat.
Vydejte se ke tmavé značce X přes modrý koberec a postavte se k terminálu. Vytvořte proměnnou blue_unpack a uložte do ní hodnotu funkce struct.unpack(), přičemž jako argumenty přidejte stejný formát, který jste použili při balení dat, a proměnnou blue_data. Formát je psán stejným způsobem jako u funkce struct.pack(), což vám umožní deserializovat data stejným způsobem, jakým jste je serializovali. Použijte funkci write() s argumentem blue_unpack pro ověření dat, která jste předtím zabalili.
Na stejném místě rovněž použijeme funkci struct.iter_unpack(). Ta přijímá přesně stejné argumenty jako struct.unpack(), nicméně je nyní formátována jako cyklus for, což nám umožní iterovat přes data, místo jejich pouhého vypsání. Funkce je kódována následovně:
for values in struct.iter_unpack(-insert value-, -insert value-): player.speak(values)
K zobrazení hodnot budeme používat funkci speak(). Pro chybějící argumenty ve funkci struct.iter_unpack() přidejte stejné hodnoty, jaké jste použili u struct.unpack(), protože se jedná o varianty téže funkce.
Vydejte se ke zlaté značce X přes červený koberec a postavte se ke stolu. Použijte funkci read() pro kontrolu množství plodin. Poznamenejte si všechna množství a formát pro každou plodinu. Vydejte se ke značce X s bílým světlem přes červený koberec a vytvořte objekt s názvem buffer a přiřaďte mu hodnotu bytearray(16). Jedná se o kolekci bajtů, do které můžete ukládat data manuálně, fungující jako datová banka. Číslo 16 udává délku, tedy kolik bajtů můžete v objektu buffer uložit.
Použijte funkci struct.pack_into() k naplnění vytvořeného objektu buffer. Není třeba vytvářet proměnnou pro uložení výsledku funkce, protože samotná funkce vloží hodnoty přímo do objektu buffer. Budete používat tuto funkci pro každý z předtím zaznamenaných datových bodů a vyplníte její argumenty.
Například, pro první hodnotu plodiny vám bude poskytnut její formát, pozice v bajtech a množství. Jako první argument přidejte formát, jako druhý objekt buffer (místo, kam se mají bajty serializovat) a jako třetí argument nastavte pozici, kam chcete hodnotu vložit; formát určuje využité bajty, takže buďte opatrní, abyste nezapsali data do již obsazeného prostoru. Nakonec přidejte hodnotu, kterou chcete serializovat a vložit do objektu buffer.
struct.pack_into('i', buffer, 0, 82)
Objekt buffer má 16 bajtů, jak bylo dříve uvedeno. V uvedeném kódu formát pro integer zabírá 4 bajty a je vložen na pozici 0. To znamená, že jakmile jsou data vložena do buffer, zbývá v objektu buffer pouze 12 volných bajtů, protože pozice 0–3 jsou obsazeny hodnotou, zde 82. Udělejte to pro všechny zaznamenané údaje o plodinách, celkem tři (3). Použijte funkci display() a předáte jí buffer pro zobrazení serializovaných dat.
Vydejte se ke tmavé značce X přes červený koberec a postavte se k terminálu. Zde budeme deserializovat data, abychom ověřili jejich obsah a zajistili tak správné uložení. Vytvořte tři proměnné s názvy: lettuce, carrots a melons. Každý datový bod rozbalíte individuálně. Pro každou proměnnou uložte hodnotu funkce struct.unpack_from() a nastavte argumenty podle dříve zaznamenaných dat. Jako první argument nastavte formát, jako druhý předávejte objekt buffer (místo, odkud se má rozbalit) a jako třetí argument pozici v buffer, odkud chcete data rozbalit. Například:
lettuce = struct.unpack_from('i', buffer, 0)
Tato data odpovídají předchozímu příkladu balení, proveďte to samé i pro zbývající dvě proměnné a vložte lettuce, carrots a melons do předem připravené funkce write() pro dokončení úrovně.