שבוע 12, יום 4: סִדרוּת, API

אדמיניסטרטיבי

היום בשעה 18:30 אעלה לשידור חי של כשעתיים, בו אענה לשאלות שנצברו אצלכם.
ביום שלישי הקרוב (20/10) אעלה בשעה 20:00 ואראה כיצד מקימים אתר קצה לקצה.

סִדרוּת (Serialization)

בקצרה, סִדרוּת (ביום־יום אומרים “סריאליזציה”), הוא תהליך של העברת מבני נתונים (כמו מילון או רשימה) לצורה בה יהיה אפשר לאחסן את מבני הנתונים בקלות, או להעביר אותו ליעד אחר.
לרוב הקלט של תהליך הסריאליזציה יהיה מבנה נתונים, והפלט יהיה טקסט כלשהו שמייצג את את אותו מבנה נתונים.
בדה־סריאליזציה (deserialization) עושים את התהליך ההפוך, שבו הקלט הוא לרוב טקסט, והפלט הוא לרוב מבנה נתונים.

שימושים נפוצים לסריאליזציה:

  1. אם נצטרך להעביר בין שני מחשבים מילון ששמור בפייתון, נוכל בקלות לעשות לו סריאליזציה במחשב בו הוא שמור ולשלוח אותו למחשב השני. המחשב השני יעשה דה־סריאליזציה, ובכך יוכל להשתמש במילון.
  2. אם נרצה לשמור על המחשב את אותו מילון, נוכל להמיר אותו לטקסט בעזרת סריאליזציה ולשמור אותו בקלות על קובץ.

על אודות JSON

ישנם פרוטוקולים שונים לסריאליזציה, המוכר שבהם הוא JSON (קיצור ל־JavaScript Object Notation).
היתרון הגדול של צורות סריאליזציה מוכרות במיוחד הוא שהן נתמכות בכל שפה שנגיע אליה. זה המצב עם JSON.
בואו נמיר tuple של מילונים בפייתון ל־JSON, ונהפוך אותה למערך של אובייקטים (המקבילה ה־JavaScript־ית) ב־JavaScript:

import json
people = ({'name': 'Hummus', 'favorite_dish': 'Moshe'}, {'name': 'Guyava', 'favorite_dish': 'Danna'})
print(json.dumps(people))

איך יראה הפלט? דומה להחריד:

[{"name": "Hummus", "favorite_dish": "Moshe"}, {"name": "Guyava", "favorite_dish": "Danna"}]

ננסה להמיר חזרה ל־Python, רק כדי לראות מה קרה כאן:

json.loads('[{"name": "Hummus", "favorite_dish": "Moshe"}, {"name": "Guyava", "favorite_dish": "Danna"}]')

קיבלנו:

[{'name': 'Hummus', 'favorite_dish': 'Moshe'},
 {'name': 'Guyava', 'favorite_dish': 'Danna'}]

שימו לב שאיבדנו את העובדה שמבנה הנתונים החיצוני היה tuple.
זה קורה כיוון שב־JSON אין מבנה נתונים שקול בדיוק ל־tuple, ולכן סריאליזציה של tuple־ים ממירה אותם לרשימות. זה בד"כ לא משהו שמשפיע עלינו באמת, אבל זה כן משהו לקחת בחשבון כשעושים סריאליזציה באמצעות JSON.

בנוסף, פייתון דאגה למיר את התו ' לתו ", כדי לעמוד בתקן של JSON.

אם נרצה לטעון באמצעות JavaScript את ה־JSON, נוכל לכתוב:

JSON.parse('[{"name": "Hummus", "favorite_dish": "Moshe"}, {"name": "Guyava", "favorite_dish": "Danna"}]')

חשוב לזכור ש־JSON נתמכת כמעט בכל פלטפורמה שתגיעו אליה – וזה החוזק העיקרי שלה.

ב־Go, לדוגמה, תוכלו לכתוב:

json.Unmarshal([]byte(myJsonString), &myStoredVariable)

וב־Java תוכלו לכתוב:

FileReader reader = new FileReader(filename);
JSONParser jsonParser = new JSONParser();
return jsonParser.parse(reader);

על אודות pickle

כפי שראינו, החיסרון המשמעותי ביותר של JSON היא איבוד מידע. JSON לא מבטיח לשמור לכם על טיפוסי הנתונים שהמרתם, ואפילו יסרב להמיר אובייקטים מורכבים (לדוגמה: רשימת תאריכים מטיפוס datetime).

כדי להתמודד עם הבעיה, פייתון מציעה את המודול הסטנדרטי pickle שמאפשר לעשות סריאליזציה לכל אובייקט פייתון שהוא. החיסרון הוא, כמובן, שמעט מאוד שפות תכנות אחרות תומכות ב־pickle ישירות מהקופסה.

נראה דוגמה ליצירת pickle:

import datetime
import pickle

pickle.dumps(datetime.datetime.now())

תוצאה:

b’\x80\x04\x95*\x00\x00\x00\x00\x00\x00\x00\x8c\x08datetime\x94\x8c\x08datetime\x94\x93\x94C\n\x07\xe4\n\x12\x073 \x04\x02\xa1\x94\x85\x94R\x94.’

תחביר

השימוש ב־pickle וב־json בפייתון זהה למדי – מייבאים את הספרייה הרלוונטית, ומשתמשים באחת מארבע פעולות שזמינות בספרייה:

  1. הפעולה load – מאפשרת לטעון מחרוזת מקובץ ולהעביר אותה דה-סריאליזציה.
  2. הפעולה loads – מאפשרת לטעון מחרוזת רגילה ולהעביר אותה דה-סריאליזציה.
  3. הפעולה dump – מאפשרת לשמור טיפוס נתונים על קובץ אחרי שעבר סריאליזציה.
  4. הפעולה dumps – מאפשרת לשמור טיפוס נתונים כמשתנה/לקבל אותו כערך אחרי שעבר סריאליזציה.

שימוש בפרויקט שלנו

ננסה להבין, לדוגמה, כיצד מערכת התרגילים מציגה לכם את ההערות שקיבלתם על התרגילים שלכם.

כדי לעשות את זה נלחץ F12 בדף התרגיל, נעבור ללשונית Networks ונלחץ על Refresh.
בין הבקשות, נוכל לראות את הבקשה לדף https://solve.pythonic.guru/comments?act=fetch&fileId=111088, כאשר 111088 הוא מספר הקובץ שהוגש.

כסיכום ביניים, אנחנו יכולים להגיד שבעת כניסה לתרגיל, המערכת פונה באמצעות בקשת GET קלאסית לדף comments בדומיין solve.pythonic.guru, שהפרמטרים שלה הם act: fetch ו־fileId: 111088.

תשובת השרת היא:

[{"author_name":"\u05d4\u05d1\u05d5\u05d3\u05e7 \u05d4\u05d0\u05d5\u05d8\u05d5\u05de\u05d8\u05d9","author_role":2,"comment_id":1725,"file_id":111088,"id":337937,"is_auto":true,"line_number":6,"text":"\u05d9\u05d1\u05d5\u05d0\u05d9 \u05d4\u05de\u05d5\u05d3\u05d5\u05dc\u05d9\u05dd \u05e9\u05dc\u05da \u05de\u05e1\u05d5\u05d3\u05e8\u05d9\u05dd \u05dc\u05d0 \u05e0\u05db\u05d5\u05df. \u05d4\u05e7\u05e4\u05d9\u05d3\u05d5 \u05dc\u05e1\u05d3\u05e8 \u05d0\u05d5\u05ea\u05dd \u05d1\u05e1\u05d3\u05e8 \u05d0\u05dc\u05e4\u05d1\u05ea\u05d9."},{"author_name":"\u05d4\u05d1\u05d5\u05d3\u05e7 \u05d4\u05d0\u05d5\u05d8\u05d5\u05de\u05d8\u05d9","author_role":2,"comment_id":1725,"file_id":111088,"id":337938,"is_auto":true,"line_number":9,"text":"\u05d9\u05d1\u05d5\u05d0\u05d9 \u05d4\u05de\u05d5\u05d3\u05d5\u05dc\u05d9\u05dd \u05e9\u05dc\u05da \u05de\u05e1\u05d5\u05d3\u05e8\u05d9\u05dd \u05dc\u05d0 \u05e0\u05db\u05d5\u05df. \u05d4\u05e7\u05e4\u05d9\u05d3\u05d5 \u05dc\u05e1\u05d3\u05e8 \u05d0\u05d5\u05ea\u05dd \u05d1\u05e1\u05d3\u05e8 \u05d0\u05dc\u05e4\u05d1\u05ea\u05d9."},{"author_name":"\u05d4\u05d1\u05d5\u05d3\u05e7 \u05d4\u05d0\u05d5\u05d8\u05d5\u05de\u05d8\u05d9","author_role":2,"comment_id":1725,"file_id":111088,"id":337939,"is_auto":true,"line_number":12,"text":"\u05d9\u05d1\u05d5\u05d0\u05d9 \u05d4\u05de\u05d5\u05d3\u05d5\u05dc\u05d9\u05dd \u05e9\u05dc\u05da \u05de\u05e1\u05d5\u05d3\u05e8\u05d9\u05dd \u05dc\u05d0 \u05e0\u05db\u05d5\u05df. \u05d4\u05e7\u05e4\u05d9\u05d3\u05d5 \u05dc\u05e1\u05d3\u05e8 \u05d0\u05d5\u05ea\u05dd \u05d1\u05e1\u05d3\u05e8 \u05d0\u05dc\u05e4\u05d1\u05ea\u05d9."}]

אם אתם משתמשים בדפדפן עם כלי פיתוח מודרניים, יתכן שהוא יבחר להציג לכם את התשובה באופן נאה לעין:

במערכת יש קוד JavaScript שקורא את הנתונים הללו, שהתקבלו משרת ה־Flask.
לפי אותם נתונים הוא צובע את השורות הרלוונטיות ומאפשר לכם ללחוץ עליהן כדי לקבל פרטים נוספים על ההערה. את שם הבודק ואת המלל שיוצגו לכם הוא לוקח מהשדות author_name ו־text שמופיעים ב־JSON.

כשתשתמשו בפרויקט שלכם ב־API, כמעט כל השירותים יאפשרו לכם לקבל תשובות ב־JSON.
כעת אתם יודעים מה זה הייצוג הזה, וכיצד להמיר אותו לטיפוס נתונים שאתם מכירים בפייתון.


מה זה API?

המונח API הוא ראשי תיבות של Application Programming Interface.
תוכנות פופולריות רבות כמו Facebook, Telegram או אפילו מערכת הפורומים שלנו, רוצות לעזור למתכנתים לכתוב עבורם הרחבות ולהשתמש באותן תוכנות לצורכיהם בקלות.

לשם כך אותן תוכנות כותבות עבור המתכנתים דרך נוחה וקלה לדבר איתן. לזה קוראים API.
אותו API לרוב מתועד, כך שאם תרשמו Discourse API לדוגמה (זה השם של מערכת הפורומים שלנו) אתם תראו הוראות שימוש מפורטות.

דוגמאות ל־API:

  • מערכת הפורומים שלנו יודעת להחזיר בצורת JSON את כל ההודעות הפרטיות שלכם, או אפילו לשנות תמונת פרופיל באמצעות ה־API.
  • ב־Telegram אפשר ליצור בוט שמתממשק עם הערוץ, מקבל את כל המידע ממנו ויודע לבצע כל פעולה שמשתמש רגיל יכול לעשות, מהזמנת משתמשים ועד להשעייתם.
  • גם ל־Facebook, Youtube, Twitter, Whatsapp ואפילו ל־Windows – יש API.

על אודות Flask

המודול Flask הוא מודול מינימליסטי שמאפשר לכם להרים שרת web בסיסי באמצעות פייתון.
ראו את הלייב ביום 3 ואת דוגמת הקוד שמצורפת אליו כדי להבין כיצד הוא עובד ומה ניתן לעשות בעזרתו.

אפליקציית Flask בסיסית (תודה לוויקיפדיה):

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run(debug=True)
7 לייקים

היי הייתי שמח לשני חידודים,
אחד מה כרגע הדברים שנדרש לבצע חוץ מלהעמיד אתר…אלא קצת יותר ספציפי… פשוט מרגיש שהשבוע חלקנו נאבדנו כי היינו רגליים למשימות ספציפיות
ב. עוד קצת הסברים שלך על פלאסק אם זה יהיה אפשרי

2 לייקים

היי ים,
האם כל API נכתב כjson ומחזיר תשובה באמצעות json ?
האם יש מקום שאתה ממליץ שנוכל לקרוא בו מידע נוסף על איך יוצרים API ?
תודה

אשמח אם תסביר על REST API.

תודה רבה על המענה בשידור!

לייק 1
  1. הסבר מעולה !
  2. כדי שהדפדפן יציג json בצורה יפה , בדרך כלל נדרשת התקנת תוסף לדפדפן.