Курс по усъвършенствано разработване с Python
Глава
>
Ниво
Модули за сериализация
Модул за структури
Цел
Настройте окончателното разпределение на данните за новата земеделска земя, използвайки модула struct.
В края на пътя има сервизна станция, която администрира новата земеделска земя, която вече е изградена, и културите, които вече са засадени. Тук ще инспектираме и обработим данните за засадените култури и прогнозираната продукция на земеделското стопанство. Подобно на другите нива в тази глава, ще работим със сериализация и десериализация на данни, като въведем един фин модул, наречен struct.
Модулът struct въвежда серия от функции за сериализация, които опакови данните в бинарен формат. За разлика от другите модули, с които сме работили, имате по-голям контрол върху това как можем да структурираме данните както при тяхната сериализация, така и при последващата десериализация, което го прави по-гъвкав от другите модули. Използвайте import struct, за да получите достъп до следните функции, които ще използваме за обработка на данните:
struct.calcsize(): Определя колко байта заема даден низ от формати, приема един (1) аргумент - формата, чийто размер в байтове искате да проверите. Форматите, които ще използваме, са:- integer: представен като
'i'е форматът за данни, представени като цели числа - float: представен като
'f'е форматът за данни, представени като десетични числа - double: представен като
'd'е форматът за данни, представени като по-сложни десетични числа, при които форматът float не е достатъчен.
- integer: представен като
struct.pack(): Сериализира данни в бинарен формат, опаковайки ги в избран от вас формат. Може да приема два (2) или повече аргументи, като първият е форматът, който искате да използвате, а останалите са стойностите, които искате да сериализирате. Форматите са тези, описани по-горе, и трябва да ги добавяте в съответствие с броя на аргументите, които подавате.struct.unpack(): Десериализира опаковани бинарни данни, приема два (2) аргумента - формата, в който трябва данните да се сравнят с формата, в който са сериализирани, и вторият е данните, които са сериализирани.struct.iter_unpack(): Десериализира опаковани бинарни данни, работи по същия начин катоstruct.unpack(), но итерирате през всеки блок данни индивидуално чрез използването на цикъл.struct.pack_into(): Разширена версия наstruct.pack(), приема четири (4) аргумента: формата, който искате да използвате, буфера за данни, в който искате да поставите данните, позицията в буфера, която данните да заемат, и накрая данните, които опаковате.struct.unpack_from(): Разширена версия наstruct.unpack(), приема три (3) аргумента: формата, който искате да използвате, буфера за данни, от който искате да десериализирате, и накрая местоположението в буфера, от което искате да извлечете данните. Това ви позволява да десериализирате конкретни части от данните.
Придвижете се към светлия Х-образен знак в сервизната станция и обърнете се към бюрото, създайте три (3) променливи, наречени: integer, float и double. Ще ги използваме, за да проверим размера в байтове за всеки формат, като използваме функцията struct.calcsize(). За променливата integer използвайте функцията с аргумент 'i', за променливата float използвайте функцията с аргумент 'f' и накрая за променливата double използвайте функцията с аргумент 'd'. Например: integer = struct.calcsize('i'). Добавете трите (3) променливи към предварително написаната функция write().
Придвижете се към златния Х-образен знак и използвайте функцията read(), за да съберете данни за новата земеделска земя, отбележете си данните и формата им за бъдеща употреба, а именно: Resources, Size и Estimate. След като си запишете тези данни, придвижете се към светлия Х-образен знак над синия килим и създайте променлива, наречена blue_data.
В променливата blue_data съхранете стойността на функцията struct.pack(), задавайки като аргументи формата и стойностите, които си отбелязахте по-рано. Когато пишете формата, вие трябва да "опаковате" типовете формати в единна единица. Например, форматът за цяло число е обозначен като 'i', както беше описано по-горе; ако добавяте три цели числа, тяхното представяне ще бъде като 'iii'. По същия начин, ако добавяте едно цяло число, един плаващ и едно двойно число, форматът ще бъде написан като 'ifd'. При добавянето на данните ги поставяте индивидуално като аргументи. Ето един общ пример:
data_1 = 8 # е цяло число data_2 = 2.25 # е плаващо число data_3 = 900.702938103 # е двойно число blue_data = struct.pack('ifd', data_1, data_2, data_3)
Функцията struct.pack() позволява много гъвкавост, като ви дава възможност да определите как искате да форматирате данните и ви позволява да сериализирате множество данни едновременно, според вашето усмотрение. Добавете предварително прочетените данни, използвайки примера по-горе като основа. Използвайте функцията display() с blue_data като аргумент, за да видите опакованите данни.
Придвижете се към тъмния Х-образен знак над синия килим и обърнете се към терминала, създайте променлива, наречена blue_unpack, и съхранете стойността на функцията struct.unpack(), като добавите същия формат, използван за опаковане на данните, и променливата blue_data като аргументи. Форматът се пише по същия начин, както при функцията struct.pack(), така че да можете да десериализирате данните по същия начин, по който първоначално са били сериализирани. Използвайте функцията write() с blue_unpack като аргумент, за да проверите данните, които преди това опаковахте.
На същото място ще използваме и функцията struct.iter_unpack(). Тя приема точно същите аргументи като struct.unpack(), но сега е форматирана като цикъл for, което ни позволява да итерираме през данните, вместо просто да ги изведем наведнъж. Функцията е кодифицирана по следния начин:
for values in struct.iter_unpack(-insert value-, -insert value-): player.speak(values)
Ще използваме функцията speak() за да изведем стойностите. За липсващите аргументи във функцията struct.iter_unpack(), добавете същите, които използвахте при struct.unpack(), тъй като става дума за варианти на една и съща функция, по отношение на начина на използване.
Придвижете се към златния Х-образен знак над червения килим и обърнете се към бюрото, използвайте функцията read(), за да прегледате количествата на културите. Отбележете си всички количества и формата за всяка култура. Придвижете се към светлия Х-образен знак над червения килим и създайте обект, наречен buffer, като му присвоите стойността bytearray(16). Това е колекция от байтове, към която можем да имаме достъп преди да я запълним. За нашите цели тя работи като банк за данни, в който можете да съхранявате данни ръчно. Числото 16 като аргумент задава дължината на байтовете, които можете да съхраните в обекта buffer.
Използвайте функцията struct.pack_into(), за да запълните създадения от вас обект buffer. Няма нужда да създавате променлива, за да съхраните стойността на функцията, тъй като функцията директно вмъква стойностите в обекта buffer. Ще използваме функцията за всяка от стойностите, които преди това сте отбелязали, като попълните аргументите й.
Например, за първата стойност на културата, която ви е предоставена, ще получите нейния формат, нейната позиция в байтовете и количеството й. Добавете формата за първия аргумент, позицията, в която желаете да сериализирате байтовете (в този случай buffer). За третия аргумент задайте позицията, в която искате да добавите стойността вътре в buffer - форматът определя колко байта се заемат, така че бъдете внимателни да не презапишете данни, които вече са там. Накрая добавете стойността, която искате да сериализирате и опаковате в обекта buffer.
struct.pack_into('i', buffer, 0, 82)
Обектът buffer има 16 байта, както беше посочено по-рано. В предоставения по-горе код, форматът за цяло число заема 4 байта и се вмъква на позиция 0. Това означава, че след като данните бъдат вмъкнати в buffer, остават само 12 байта свободни в buffer, като позициите от 0 до 3 са заети със стойността, предоставена в този случай – 82. Направете това за всички данни за културите, които преди това сте прочели и отбелязали, като общият им брой е три (3). Използвайте функцията display() и добавете buffer, за да изведете сериализираните данни.
Придвижете се към тъмния Х-образен знак над червения килим и обърнете се към терминала. Тук ще десериализираме данните, за да проверим съдържанието и да се уверим, че са съхранени правилно. Създайте три променливи, наречени: lettuce, carrots и melons, и ще десериализираме данните за всяка от тях поотделно. За всяка променлива съхранете стойността на struct.unpack_from() и задайте като аргументи същите данни, които сте отбелязали при опаковането. За първия аргумент задайте формата, за втория аргумент добавете обекта buffer, който е мястото, от което ще десериализирате, и накрая позицията в buffer, от която желаете да извлечете данните. Например:
lettuce = struct.unpack_from('i', buffer, 0)
Тези данни съответстват на предишния пример за опаковане, който сега се десериализира. Направете същото и за двете останали променливи и добавете lettuce, carrots и melons към предварително написаната функция write(), за да завършите нивото.