פייתון: שימוש ב Named Tuple בעבודה עם JSON

16/05/2018

בעבודה עם אוביקטי JSON הרבה פעמים נוח לשמור את האוביקט כולו ב Named Tuple - כך נקבל וולידציה על השדות וגם גישה מהירה באמצעות אופרטור הנקודה. קבלו דוגמא קצרה וגם ממה להיזהר.

1. איך זה עובד

המבנה Named Tuple מחזיק אוסף ערכים לקריאה בלבד ומספק קריאה מהירה מהם דרך אופרטור הנקודה. תזכורת לאיך הוא עובד אפשר לראות בקוד הבא:

from collections import namedtuple

Point = namedtuple('Point', 'x y')
p = Point(x=10,y=20)

print(f"You are at ({p.x}, {p.y})")

נמשיך להגדרת אוביקט namedtuple לייצוג מיקום:

Position = namedtuple('Position', 'latitude longitude')

ב URL הבא נוכל לקבל תמיד את מיקום תחנת החלל הבין לאומית כאוביקט JSON:

http://api.open-notify.org/iss-now.json

באמצעות המודול requests אפשר לקבל את ה JSON הזה ולהדפיס את השדות. התקינו את requests עם הפקודה:

pip install requests

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

mport requests
r = requests.get('http://api.open-notify.org/iss-now.json')
r.raise_for_status()
pos = r.json()

lat = pos['iss_position']['latitude']
lng = pos['iss_position']['longitude']
print(f'ISS is at: {lat}, {lng}')

עכשיו אנחנו מוכנים לחבר Named Tuple. הקוד הבא משתמש ב Named Tuple כדי לספק גישה מהירה לשדות וגם וולידציה:

import requests
from collections import namedtuple

Position = namedtuple('Position', 'latitude longitude')
r = requests.get('http://api.open-notify.org/iss-now.json')
r.raise_for_status()

json = r.json()['iss_position']
pos = Position(**json)

lat = pos.latitude
lng = pos.longitude
print(f'ISS is at: {lat}, {lng}')

2. מחשבות להמשך

  1. חיסרון אחד בגישה הוא ה Validation על השדות. במידה והשירות מוריד שדה כל העסק ייפול וזה מצוין, אבל גם במידה והוא מוסיף שדה הבנאי של Position יתלונן על שדה מיותר והעסק ייפול. בגדול APIs לא אמורים להשתנות וכשמשנים אותם נהוג להעלות גירסא אז לא בטוח שזה בעיה. תלוי מול מי אתם עובדים.

  2. אם מוותרים על ה Validation ורוצים להישאר רק עם הגישה המהירה אפשר לבנות את ה NamedTuple באופן דינמי לפי אוביקט ה JSON שהגיע. דוגמא לקוד שעושה את זה תוכלו למצוא בקישור הבא: https://gist.github.com/hangtwenty/5960435