بيانات متداخلة كنص
JSON هو الصيغة اليومية لملفات الإعداد وللبيانات المتبادلة بين البرامج وواجهات الويب. يتكوّن من كائنات {"key": value} ومصفوفات [1, 2] ونصوص وأرقام وtrue/false وnull. وهي تقابل بايثون مباشرة: تصبح الكائنات قواميس، والمصفوفات قوائم، وتصبح true/false هي True/False، وتصبح null هي None. وعلى خلاف جدول CSV يمكن لـJSON أن يتداخل: يستطيع أمر أن يحمل قائمة تنفيذات لكل منها حقولها.
import json
# Text to Python: loads() ("load string")
text = '{"symbol": "AAPL", "fills": [{"price": 184.25, "qty": 100}], "open": true, "note": null}'
order = json.loads(text)
print(order["fills"][0]["price"]) # 184.25
print(order["open"], order["note"]) # True None
# Python to text: dumps() ("dump string")
print(json.dumps({"symbol": "AAPL", "qty": 200})) # {"symbol": "AAPL", "qty": 200}الملفات: load و dump
النسخ التي بلا s تعمل على الملفات: json.load(file) تقرأ ملفًا مفتوحًا وتحلله، وjson.dump(data, file) تكتبه. مرّر indent=2 ليكون الملف مقروءًا للبشر وsort_keys=True لترتيب مفاتيح ثابت، مما يُبقي الفروقات صغيرة في التحكم بالإصدارات. افتح دائمًا بـwith وencoding="utf-8".
import json
# Save a config, then load it back
config = {"fee": 0.001, "symbols": ["MSFT", "AAPL"], "limits": {"max_qty": 500}}
with open("config.json", "w", encoding="utf-8") as file:
json.dump(config, file, indent=2, sort_keys=True)
with open("config.json", encoding="utf-8") as file:
print(file.read())
# {
# "fee": 0.001,
# "limits": {
# "max_qty": 500
# },
# "symbols": [
# "MSFT",
# "AAPL"
# ]
# }
with open("config.json", encoding="utf-8") as file:
print(json.load(file) == config) # Trueما لا ينجو من الرحلة
لا يملك JSON إلا أنواعًا قليلة، فتتغير بعض قيم بايثون في الطريق. تعود الصفوف قوائم، وتعود مفاتيح القواميس دائمًا نصوصًا ({1: "a"} تعود {"1": "a"})، ولا يمكن تفريغ المجموعات والتواريخ والكائنات المخصصة أبدًا (TypeError) حتى تحوّلها، كتاريخ بـ.isoformat() أو مجموعة بـsorted(...). وتذكّر أن NaN واللانهاية ليستا JSON صالحًا.
import json
from datetime import date
# Tuples become lists, int keys become strings
data = {"pair": (1, 2), 7: "seven"}
print(json.loads(json.dumps(data))) # {'pair': [1, 2], '7': 'seven'}
# A date has to be converted by hand
today = date(2025, 1, 2)
print(json.dumps({"day": today.isoformat()})) # {"day": "2025-01-02"}مدخلات سيئة
قد لا يكون النص الذي يصل من الخارج، كرسالة من بورصة، JSON صالحًا أصلًا. عندها ترفع json.loads الخطأ json.JSONDecodeError، وهو نوع من ValueError، وقد يفتقر JSON الصالح إلى المفتاح المطلوب (KeyError) أو يكون على شكل آخر (TypeError). ضع التحليل داخل try/except وقرّر ما تعنيه الرسالة السيئة لبرنامجك. يغطي الموضوع التالي الاستثناءات بالكامل.
import json
# Bad input raises, so catch it where you parse
def get_price(text):
try:
return json.loads(text)["price"]
except (ValueError, KeyError, TypeError):
return None
print(get_price('{"price": 184.25}')) # 184.25
print(get_price("not json")) # None
print(get_price('{"symbol": "AAPL"}')) # Nonejson.dumps أو json.dump تنتج النص، ودع json.loads أو json.load تقرؤه. والأمر نفسه عند دمج الإعدادات: انسخ قبل التغيير حتى لا يتسرب إعداد إلى آخر.json.loads(text)/json.dumps(data)للنصوص؛ وjson.load(file)/json.dump(data, file)للملفات.indent=2وsort_keys=Trueتجعلان الملفات مقروءة وثابتة.- المدخلات السيئة ترفع
ValueErrorأوKeyErrorأوTypeError: التقط ما تتوقعه.
التالي: الاستثناءات ومعالجة الأخطاء، لتفشل برامجك بوضوح وتتعافى عند اللزوم.
المختبر: ما الذي يُقيَّم
- اجمع الأوامر في ملف JSON باستخدام
order_total25 نقطة - احفظ الإعدادات بصيغة JSON مقروءة باستخدام
save_config25 نقطة - اقرأ رسالة عرض سعر بأمان باستخدام
parse_quote25 نقطة - ضع الإعدادات فوق القيم الافتراضية باستخدام
merge_configs25 نقطة