Curs avansat de dezvoltare în Python
Capitolul
>
Nivel
Module de serializare
Modul Struct
Obiectiv
Configurează despărțirea finală a datelor pentru noua fermă folosind modulul struct.
La capătul drumului se află o stație de serviciu care administrează noua fermă deja construită și culturile deja plantate. Aici vom inspecta și procesa datele pentru culturile deja plantate și producția estimată a fermei. La fel ca la celelalte niveluri din acest capitol, vom lucra cu serializarea și deserializarea datelor, introducând un ultim modul numit modulul struct.
Modulul struct introduce o serie de funcții de serializare care împachetează date în format binar, spre deosebire de celelalte module cu care am lucrat, ai totuși un control mai mare asupra modului în care structurate sunt datele atât la serializare, cât și la deserializare, făcându-l mai versatil decât alte module. Folosește import struct pentru a accesa următoarele funcții pe care le vom folosi pentru a procesa datele:
struct.calcsize(): Determină câți octeți ocupă un șir de format dat; primește un (1) argument, formatul pentru care dorești să verifici dimensiunea în octeți. Formatele pe care le vom folosi sunt:- integer: reprezentat prin
'i'este formatul pentru date reprezentate prin numere întregi - float: reprezentat prin
'f'este formatul pentru date reprezentate prin numere zecimale - double: reprezentat prin
'd'este formatul pentru date reprezentate prin numere zecimale mai complexe, unde formatul float este insuficient.
- integer: reprezentat prin
struct.pack(): Serializează date în format binar, împachetate într-un format la alegerea ta. Poate primi două (2) sau mai multe argumente: formatul pe care dorești să îl folosești și valorile pe care vrei să le serializezi. Formatele sunt cele descrise anterior și trebuie adăugate corespunzător numărului de argumente pe care le adaugi.struct.unpack(): Deserializare date binare împachetate; primește două (2) argumente: formatul în care trebuie să fie comparabil cu formatul în care a fost serializat și, al doilea, datele care au fost serializate.struct.iter_unpack(): Deserializare date binare împachetate; funcționează la fel castruct.unpack(), dar iterează prin fiecare bloc de date individual folosind un ciclu.struct.pack_into(): O versiune avansată astruct.pack(); primește patru (4) argumente: formatul pe care dorești să îl folosești, buffer-ul de date în care vrei să introduci datele, poziția în buffer la care vrei ca datele să ocupe și, în final, datele pe care le împachetezi.struct.unpack_from(): O versiune avansată astruct.unpack(); primește trei (3) argumente: formatul pe care dorești să îl folosești, buffer-ul de date din care vrei să decomprimi și, în final, locația în buffer de unde vrei să decomprimi. Acest lucru îți permite să decomprimi porțiuni specifice din date.
Mergi la semnul X luminat în stația de serviciu și stai cu fața spre birou, creează trei (3) variabile numite: integer, float și double. Le vom folosi pentru a verifica dimensiunea în octeți a fiecărui format folosind funcția struct.calcsize(). Pentru variabila integer folosește funcția cu 'i' ca argument, pentru variabila float folosește funcția cu 'f' ca argument și în final pentru variabila double folosește funcția cu 'd' ca argument. De exemplu: integer = struct.calcsize('i'). Adaugă cele trei (3) variabile în funcția write() pre-scrisă.
Mergi la semnul X auriu și folosește funcția read() pentru a colecta date despre noua fermă, notează punctele de date și formatul pentru utilizare ulterioară, și anume: Resources, Size și Estimate. După ce le notezi, mergi la semnul X luminat de pe covorul albastru și creează o variabilă numită blue_data.
În variabila blue_data stochează valoarea funcției struct.pack(), setând ca argumente formatul și valorile pe care le-ai notat anterior. Când scrii formatul, trebuie să „împachetezi” tipurile de format într-o singură unitate. De exemplu, formatul integer este etichetat 'i' după cum s-a detaliat anterior; dacă adaugi trei tipuri de date integer, le adaugi ca 'iii'. În același mod, dacă adaugi un integer, un float și un double, ar fi scris 'ifd'. Când adaugi datele, le plasezi individual ca argumente. Iată un exemplu general:
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)
Funcția struct.pack() permite o mare flexibilitate, oferindu-ți posibilitatea să stabilești cum să formatezi datele și să serializi mai multe puncte de date odată, după cum dorești. Adaugă datele citite anterior folosind exemplul de mai sus ca bază. Folosește funcția display() cu blue_data ca argument pentru a vizualiza datele împachetate.
Mergi la semnul X întunecat de pe covorul albastru și stai cu fața la terminal, creează o variabilă numită blue_unpack și stochează valoarea funcției struct.unpack(), adăugând același format folosit pentru a împacheta datele și variabila blue_data ca argumente. Formatul este scris în același mod ca la struct.pack(), astfel încât să poți deserializa datele în aceeași manieră în care le-ai serializat inițial. Folosește funcția write() cu blue_unpack ca argument pentru a verifica datele pe care le-ai împachetat anterior.
În aceeași locație, vom folosi și funcția struct.iter_unpack(). Aceasta primește exact aceleași argumente ca struct.unpack(), însă acum este formatată sub forma unui ciclu for, ceea ce ne permite să iterăm datele, spre deosebire de afișarea lor integrală. Funcția este scrisă astfel:
for values in struct.iter_unpack(-insert value-, -insert value-): player.speak(values)
Vom folosi funcția speak() pentru a afișa valorile; pentru argumentele lipsă din funcția struct.iter_unpack(), adaugă aceleași argumente folosite anterior cu struct.unpack(), deoarece acestea sunt variații ale aceleiași funcții, din punct de vedere al utilizării.
Mergi la semnul X auriu de pe covorul roșu și stai cu fața la birou; folosește funcția read() pentru a revizui cantitățile de cultură. Notează toate cantitățile și formatul pentru fiecare cultură. Mergi la semnul X luminat de pe covorul roșu și creează un obiect numit buffer, și adaugă valoarea bytearray(16). Aceasta este o colecție de octeți pe care îi putem adresa înainte de a o popula; pentru scopurile noastre, funcționează ca un banc de date în care poți stoca manual datele. Numărul 16 ca argument reprezintă lungimea maximă a octeților pe care îi poți stoca în obiectul buffer.
Folosește funcția struct.pack_into() pentru a popula obiectul buffer pe care l-ai creat. Nu este necesar să creezi o variabilă pentru a stoca valoarea funcției deoarece funcția însăși va introduce valorile direct în obiectul buffer. Vom folosi funcția pentru fiecare dintre valorile pe care le-am notat anterior și vom popula argumentele acesteia.
De exemplu, pentru prima valoare de cultură furnizată, îți vor fi oferite formatul, poziția în octeți și cantitatea. Adaugă formatul ca prim argument, locația în care dorești să serializezi octeții, care în acest caz este buffer. Pentru al treilea argument, setează poziția la care dorești să adaugi valoarea în interiorul buffer; formatul determină octeții folosiți, așa că asigură-te că împachetezi date care nu sunt deja ocupate. În final, adaugă valoarea pe care dorești să o serializezi și să o împacheți în obiectul buffer.
struct.pack_into('i', buffer, 0, 82)
Obiectul buffer are 16 octeți, după cum s-a menționat anterior; în codul de mai sus, formatul integer are 4 octeți și este inserat la poziția 0. Aceasta înseamnă că, odată introduse datele în buffer, rămân doar 12 octeți neocupați în buffer, pozițiile 0-3 fiind ocupate de valoarea furnizată, în acest caz 82. Fă aceasta pentru toate punctele de date ale culturilor citite și notate anterior; sunt trei (3) în total. Folosește funcția display() și adaugă buffer pentru a afișa datele serializate.
Mergi la semnul X întunecat de pe covorul roșu și stai cu fața la terminal; aici vom deserializa datele pentru a verifica conținutul și a asigura stocarea corectă. Creează trei variabile numite: lettuce, carrots și melons; vom decomprima datele fiecărui punct de date individual. Pentru fiecare variabilă, stochează valoarea struct.unpack_from() și setează argumentele folosind aceleași date pe care le-ai notat pentru împachetare. Pentru primul argument setează formatul, al doilea adaugă obiectul buffer care este locația din care se va decomprima și, în final, adaugă poziția din buffer de unde dorești să decomprima. De exemplu:
lettuce = struct.unpack_from('i', buffer, 0)
Aceste date corespund exemplelor anterioare de împachetare care sunt decomprimate; fă aceeași pentru celelalte două variabile și inserează lettuce, carrots și melons în funcția write() pre-scrisă pentru a finaliza nivelul.