קורס פיתוח מתקדם בפייתון
פרק
>
רמה
מודולי סריאליזציה
מודול Struct
מטרה
הגדר את הפירוט הסופי של הנתונים עבור השטח החקלאי החדש באמצעות מודול struct.
בסוף הדרך יש תחנת שירות המנהלת את השטח החקלאי החדש שכבר נבנה והגידולים כבר ניטעו. כאן נבחן ונטפל בנתונים של הגידולים שכבר ניטעו ובתפוקה החזויה של השטח החקלאי. כמו בשלבים אחרים בפרק זה, נעבוד עם סיריאליזציה (serialization) ודסיריאליזציה (deserialization) של נתונים, ונציג מודול אחרון בשם struct.
מודול struct מציג סדרה של פונקציות סיריאליזציה שמדחסות נתונים בפורמט בינארי. בניגוד למודולים אחרים שעבדנו איתם, כאן יש לך שליטה רבה יותר על אופן מבנה הנתונים גם בזמן הסיריאליזציה וגם בזמן הדסיריאליזציה, מה שהופך אותו לוורסטילי יותר ממודולים אחרים. השתמש ב-import struct כדי לגשת לפונקציות הבאות שנשתמש בהן לעיבוד הנתונים:
struct.calcsize(): קובעת כמה בתים תופס מחרוזת פורמט נתונה, היא לוקחת ארגומנט אחד (1) שמציין את הפורמט שברצונך לבדוק את גודל הבייטים שלו. הפורמטים שבהם נשתמש הם:- integer: מיוצג על ידי
'i', זהו הפורמט לנתונים המיוצגים במספרים שלמים - float: מיוצג על ידי
'f', זהו הפורמט לנתונים המיוצגים במספרים עשרוניים - double: מיוצג על ידי
'd', זהו הפורמט לנתונים עשרוניים מתקדמים יותר שבהם פורמט float לא מספיק.
- integer: מיוצג על ידי
struct.pack(): מבצעת סיריאליזציה של נתונים לבינארי, מדחסת אותם לפי פורמט לבחירתך. היא יכולה לקבל שני ארגומנטים או יותר, כאשר הארגומנט הראשון הוא הפורמט שברצונך להשתמש בו, והשאר הם הערכים שברצונך לסיריאליזציה. הפורמטים הם אלה שתוארו קודם, ויש להוסיף אותם בהתאמה למספר הארגומנטים.struct.unpack(): מבצעת דסיריאליזציה של נתונים בינאריים דחוסים, לוקחת שני ארגומנטים: הפורמט שבו סיריאליזנו את הנתונים, והנתונים עצמם.struct.iter_unpack(): מבצעת דסיריאליזציה של נתונים בינאריים דחוסים, פועלת כמוstruct.unpack()אך מאפשרת איטרציה על כל בלוק נתונים בנפרד באמצעות לולאה.struct.pack_into(): גרסה מתקדמת שלstruct.pack(), מקבלת ארבעה (4) ארגומנטים: הפורמט שברצונך להשתמש בו, ה-buffer שבו תמקם את הנתונים, המיקום בתוך ה-buffer שבו תדחוס את הנתונים, ולבסוף את הנתונים עצמם.struct.unpack_from(): גרסה מתקדמת שלstruct.unpack(), לוקחת שלושה (3) ארגומנטים: הפורמט שבו ברצונך להשתמש, ה-buffer שממנו תרצה לדסיריאליזציה, ולבסוף המיקום בתוך ה-buffer שממנו תחל את הדסיריאליזציה. זה מאפשר לך לדסיריאליזציה חלקים ספציפיים של הנתונים.
התקדם לסימון ה-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(), כאשר הארגומנטים הם הפורמט והערכים שרשמת קודם. בעת כתיבת מחרוזת הפורמט, אתה צריך "לארוז" (pack) את סוגי הפורמטים ביחד ביחידה אחת. לדוגמה, פורמט integer מסומן כ-'i' כפי שתואר קודם; אם מוסיפים שלושה ערכי integer מוסיפים 'iii'. באותה צורה, אם מוסיפים integer, float ו-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(), כאשר הארגומנטים הם אותו פורמט שבו השתמשת ל-pack והמשתנה 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 שבו ברצונך למקם את הערך — הפורמט קובע כמה בתים יתפוסו, לכן שים לב לא למקם על בתים שכבר תפוסים. לבסוף הוסף את הערך שברצונך לסריאליזציה ולדחיסה לתוך ה-buffer.
struct.pack_into('i', buffer, 0, 82)
לאובייקט buffer יש 16 בתים כפי שצוין קודם. בקוד שלמעלה פורמט integer תופס 4 בתים ומוכנס בתחילת ה-buffer, במיקום 0. משמעות הדבר היא שברגע שהנתונים מוכנסים ל-buffer ישנם רק 12 בתים פנויים (המיקומים 0–3 תפוסים על ידי הערך 82). בצע זאת עבור כל נקודות הנתונים של התבואה שקראת ורשמת — בסך הכול שלוש (3). השתמש בפונקציית display() והעבר לה את buffer כדי להציג את הנתונים הסיריאליים.
התקדם לסימון הכהה (X) על השטיח האדום והתייצב מול הטרמינל. כאן נדסיריאליזציה של הנתונים כדי לאמת את התכולה ולהבטיח אחסון תקין. צור שלושה משתנים בשם lettuce, carrots ו-melons. נפרק כל אחד מנקודות הנתונים בנפרד. בכל משתנה שמור את התוצאה של struct.unpack_from() והעבר לה את אותם ארגומנטים שבהם השתמשת לדחיסת הנתונים. עבור הארגומנט הראשון הצב את הפורמט, השני הוא האובייקט buffer שממנו נדסיריאליזציה, ולבסוף הוסף את המיקום בתוך ה-buffer שממנו תרצה לדסיריאליזציה. לדוגמה:
lettuce = struct.unpack_from('i', buffer, 0)
נתון זה תואם לדוגמה הקודמת של הדחיסה שמפורק כאן. בצע את אותו תהליך לשני המשתנים הנותרים והעבר את lettuce, carrots ו-melons לפונקציית write() הכתובה מראש כדי להשלים את השלב.