Coding for KidsCoding for Kids
Креативні РівніВикликиПосібник для Вчителів
Голосувати за функції
Поглиблений курс розробки на Python
Розділ
>
Рівень

Серіалізація-модулі
Структурний модуль

Мета

Налаштуйте остаточний розподіл даних для нового сільськогосподарського угіддя за допомогою модуля struct.

В кінці дороги знаходиться сервісна станція, яка обслуговує нове сільськогосподарське угіддя, що вже побудоване, та культури, що вже висаджені. Тут ми будемо перевіряти та обробляти дані щодо вже висаджених культур та прогнозованого врожаю. Як і на інших рівнях цього розділу, ми будемо працювати з серіалізацією та десеріалізацією даних, вводячи один фінальний модуль — модуль struct.

Модуль struct вводить серію функцій серіалізації, які упаковують дані у бінарному форматі, на відміну від інших модулів, з якими ми працювали. Однак, у вас є більший контроль над тим, як ми можемо структурувати дані як при серіалізації, так і при подальшій десеріалізації, що робить його більш універсальним. Використовуйте import struct, щоб отримати доступ до наступних функцій, які ми будемо використовувати для обробки даних:

  • struct.calcsize(): Визначає, скільки байтів займає заданий рядок формату; приймає один (1) аргумент — формат, розмір якого в байтах ви хочете перевірити. Формати, які ми будемо використовувати, це:
    • integer: представлений як 'i' — формат для даних, що виражені цілими числами
    • float: представлений як 'f' — формат для даних, що виражені десятковими числами
    • double: представлений як 'd' — формат для даних, що виражені більш складними десятковими числами, коли формат float є недостатнім.
  • struct.pack(): Серіалізує дані у бінарному форматі, упаковуючи їх у формат за вашим вибором. Може приймати два (2) або більше аргументів: формат, який ви бажаєте використати, та значення, які ви хочете серіалізувати. Формати є тими, що були описані раніше, і їх потрібно додавати відповідно до кількості аргументів.
  • struct.unpack(): Десеріалізує упаковані бінарні дані, приймає два (2) аргументи: перший — формат, який має відповідати формату, у якому дані були серіалізовані, а другий — серіалізовані дані.
  • struct.iter_unpack(): Десеріалізує упаковані бінарні дані, працює так само, як struct.unpack(), але ітерує кожен блок даних окремо за допомогою циклу.
  • struct.pack_into(): Розширена версія struct.pack(), приймає чотири (4) аргументи: формат, який ви хочете використати, буфер даних, у який ви бажаєте вставити дані, позицію в буфері, яку дані повинні займати, та значення, що упаковуються.
  • struct.unpack_from(): Розширена версія struct.unpack(), приймає три (3) аргументи: формат, який ви хочете використати, буфер даних, з якого потрібно розпакувати, і позицію в буфері, з якої потрібно розпакувати дані. Це дозволяє розпаковувати конкретні частини даних.

Пройдіть до світлої X позначки на сервісній станції та зверніться до столу, створіть три (3) змінні з іменами: integer, float та double. Ми будемо використовувати їх для перевірки розміру кожного формату в байтах за допомогою функції struct.calcsize(). Для змінної integer використовуйте функцію з аргументом 'i', для змінної float — з аргументом 'f', а для змінної double — з аргументом 'd'. Наприклад: integer = struct.calcsize('i'). Додайте ці три змінні до заздалегідь написаної функції write().

Пройдіть до золотої X позначки та використовуйте функцію read(), щоб зібрати дані про нове сільськогосподарське угіддя, зверніть увагу на точки даних та формат для подальшого використання, а саме: Resources, Size і Estimate. Після того, як ви зробите запис, пройдіть до світлої X позначки через синій килим і створіть змінну з ім'ям blue_data.

У змінну blue_data збережіть результат виконання функції struct.pack(), передаючи як аргументи формат і значення, які ви зауважили раніше. При записі формату ви повинні «запакувати» типи форматів в один єдиний рядок. Наприклад, формат для цілого числа позначається як 'i', як було детально описано, і якщо ви додаєте три цілих числа, ви записуєте їх як 'iii'. Аналогічно, якщо додаєте ціле число, число з плаваючою комою та double, це буде записано як 'ifd'. При додаванні даних кожне значення передається окремо як аргумент. Ось загальний приклад:

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)

Функція struct.pack() надає велику гнучкість, дозволяючи вам визначити, як саме форматувати дані, та серіалізувати кілька даних одночасно, залежно від вашого бажання. Додайте раніше зібрані дані, використовуючи наведений вище приклад як основу. Використовуйте функцію display() з аргументом blue_data, щоб переглянути запаковані дані.

Пройдіть до темної X позначки через синій килим і зверніться до терміналу, створіть змінну з ім'ям 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(), оскільки це варіації однієї й тієї ж функції з точки зору використання.

Пройдіть до золотої X позначки через червоний килим і зверніться до столу, використовуйте функцію read(), щоб переглянути кількості врожаю. Зауважте всі кількості та формат для кожної культури. Пройдіть до світлої X позначки через червоний килим і створіть об'єкт з ім'ям 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 байтів вільного місця, причому позиції 03 заповнені наданим значенням, у цьому випадку — 82. Зробіть це для всіх точок даних врожаю, які ви раніше прочитали та зафіксували, їх всього три. Використовуйте функцію display() і передайте їй buffer, щоб переглянути серіалізовані дані.

Пройдіть до темної X позначки через червоний килим і зверніться до терміналу. Тут ми будемо десеріалізувати дані для перевірки вмісту та забезпечення правильного зберігання. Створіть три змінні з іменами: lettuce, carrots і melons; ми розпаковуватимемо дані кожної точки окремо. Для кожної змінної збережіть результат функції struct.unpack_from(), передаючи ті самі дані, які ви використовували для упаковки. Для першого аргументу встановіть формат, для другого додайте об'єкт buffer, з якого буде виконано розпакування, і нарешті вкажіть позицію в buffer, з якої потрібно розпакувати дані. Наприклад:

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

Ці дані відповідають попередньому прикладу упаковки, що розпаковується. Зробіть те саме для інших двох змінних і додайте lettuce, carrots і melons до заздалегідь написаної функції write(), щоб завершити рівень.

Книга Коду