Menu
العربية

JSON في بايثون: قراءة وكتابة وتحليل البيانات

تعلّم كيف تتعامل مع JSON في بايثون باستخدام مكتبة json: تحليل النصوص، القراءة من الملفات، الطباعة المنسّقة، والتعامل مع الحالات الخاصة في البيانات الحقيقية.

JSON وبايثون يتكلمان نفس اللغة

صيغة JSON هي الصيغة الافتراضية للـ APIs وملفات الإعدادات وتبادل البيانات على الويب. ولحسن حظ مبرمجي بايثون، كائن JSON يقابل مباشرةً dict في بايثون، ومصفوفة JSON تقابل list، ونص JSON يقابل str. هذا التطابق الوثيق هو ما يجعل قراءة ملف JSON بايثون وكتابته عملية من سطرين فقط.

مكتبة json في بايثون، وهي جزء من المكتبة القياسية، تتكفّل بالاتجاهين معًا.

تحويل نص JSON إلى قاموس بايثون

الدالة json.loads(text) — اختصارًا لـ "load string" — تستقبل سلسلة نصية بصيغة JSON وتُرجع كائن بايثون المقابل لها:

main.py
Output
Click Run to see the output here.

النتيجة هي dict عادي في بايثون. تتعامل مع مفاتيحه مثل أي قاموس — لا يوجد غلاف خاص بـ JSON ولا دالة .parse() تستدعيها على النتيجة.

وإذا لم يكن النص الممرَّر JSON صالحًا، فستطلق json.loads استثناء json.JSONDecodeError. رسالة الخطأ تُحدِّد رقم السطر والعمود لموضع المشكلة، وهذا غالبًا ما يكفي لاكتشاف فاصلة ناقصة أو علامة اقتباس لم يتم تهريبها.

تحويل البيانات إلى نص JSON باستخدام json.dumps

تؤدي json.dumps(data) — أي "dump string" — الدور المعاكس تمامًا: فهي تأخذ كائن بايثون وتُعيده على هيئة نص JSON:

main.py
Output
Click Run to see the output here.

قيم True وFalse وNone في بايثون تتحول تلقائياً إلى true وfalse وnull في JSON. الأرقام والسلاسل النصية تمر كما هي دون تغيير، أما القوائم فتصبح مصفوفات، والقواميس تصبح كائنات.

التنسيق المقروء لـ JSON في بايثون (Pretty Print)

الخرج الافتراضي لدالة json.dumps يكون مضغوطاً — وهذا مناسب للنقل عبر الشبكة، لكنه متعب للقراءة البشرية. مرّر indent=2 للحصول على صيغة أوضح وأسهل في القراءة:

main.py
Output
Click Run to see the output here.

ثمة خيارات أخرى في dumps تستحق المعرفة:

  • sort_keys=True — يرتّب مفاتيح الكائن أبجديًا. مفيد عندما تحتاج إلى مخرجات ثابتة ومتوقعة (ملفات الإعدادات، بيانات الاختبار، مقارنات الـ diff).
  • ensure_ascii=False — يكتب الأحرف غير الـ ASCII (مثل é أو ü أو 中 أو الحروف العربية) كما هي بدلًا من تحويلها إلى تسلسلات \u. عادةً ما يكون هذا هو الخيار الأنسب لملفات UTF-8.
  • separators=(",", ":") — يعطيك أصغر حجم ممكن للمخرجات. وإذا جمعته مع ensure_ascii=False، فستحصل على أكثر صيغة JSON بصيغة UTF-8 إحكامًا يمكن إنتاجها.

قراءة ملف JSON في بايثون

الدالة json.load(file) — بدون حرف s — تقرأ مباشرةً من كائن ملف. والنمط الشائع هو استخدامها مع with open:

import json

with open("config.json") as f:
    config = json.load(f)

print(config["version"])

ما في داعي تقرأ الملف كله كسلسلة نصية أولاً؛ الدالة json.load تقرأ مباشرة من كائن الملف.

كتابة ملف JSON في بايثون

الدالة json.dump(data, file) هي المقابلة لعملية الكتابة في الملف:

import json

data = {"created": "2026-01-01", "items": [1, 2, 3]}

with open("state.json", "w") as f:
    json.dump(data, f, indent=2)

خيار indent يشتغل هنا كمان. افتح الملف الناتج وسترى مستند JSON منسقًا بشكل جميل.

قراءة استجابة JSON من واجهة برمجية (API)

معظم مكتبات HTTP تُرجع لك البيانات كـ bytes أو نص، وأنت تستدعي json.loads لتحويلها إلى بيانات قابلة للاستخدام:

import json
import urllib.request

with urllib.request.urlopen("https://api.example.com/users/1") as response:
    text = response.read().decode("utf-8")

user = json.loads(text)
print(user["name"])

مكتبة requests (نتناولها في درس مستقل) تختصر عليك هذه الخطوة، إذ توفّر التابع .json() على كائن الاستجابة والذي يستدعي json.loads نيابةً عنك.

ماذا يستطيع JSON تمثيله وماذا لا يستطيع

نظام الأنواع في JSON أضيق من نظام الأنواع في بايثون. إليك جدول المقابلة في الاتجاهين:

بايثونJSON
dictobject
list, tuplearray
strstring
int, floatnumber
Truetrue
Falsefalse
Nonenull

لاحظ أن الـ tuple يعود بعد الترميز وفكّه على هيئة قائمة (list)، أي أن خاصيّة كونه tuple تضيع في الطريق. أما المجموعات (set) والأصناف المخصّصة وكائنات datetime فلا يمكن تحويلها إلى JSON افتراضيًا، وستصطدم بالخطأ TypeError: Object of type X is not JSON serializable.

التعامل مع datetime والكائنات المخصّصة

هناك طريقتان شائعتان لحلّ هذه المشكلة.

الطريقة الأولى: حوّل البيانات إلى بنية متوافقة مع JSON أولًا. نفّذ التحويل يدويًا في الكود، ثم مرّر قاموسًا عاديًا إلى دالة التحويل:

main.py
Output
Click Run to see the output here.

مرر دالة default=. ستقوم json.dumps باستدعائها مع كل قيمة لا تعرف كيف تحوّلها:

main.py
Output
Click Run to see the output here.

عند قراءة البيانات مرة أخرى، عليك أن تُحوِّل سلاسل ISO إلى datetime بنفسك — لأن JSON لا يحتفظ بالنوع الأصلي للبيانات.

تحويل القاموس إلى JSON والعودة منه

اختبار سريع للتأكد من أن القواميس تمر عبر JSON دون أي خلل:

main.py
Output
Click Run to see the output here.

القيم متساوية، لكنها كائنات مختلفة. وهذه في الحقيقة حيلة مفيدة جدًا — استخدام json.dumps ثم json.loads يُعتبر طريقة سريعة وبسيطة لعمل نسخة عميقة (deep copy) من أي بنية متوافقة مع JSON.

مثال عملي من الواقع

سكربت صغير يقرأ ملف إعدادات JSON، يُعدِّل أحد الحقول، ثم يحفظه مرة أخرى:

import json
from pathlib import Path

config_path = Path("settings.json")

# Load (with a default if the file doesn't exist).
if config_path.exists():
    config = json.loads(config_path.read_text())
else:
    config = {"theme": "dark", "last_opened": None}

# Update.
config["last_opened"] = "2026-01-15"

# Save, pretty-printed.
config_path.write_text(json.dumps(config, indent=2, ensure_ascii=False))

هكذا تكتمل دورة "قراءة، تعديل، كتابة" لملفات JSON في أقل من اثني عشر سطرًا.

بعض العادات الجيدة

  • استخدم دائمًا with open(...) عند التعامل مع الملفات. فملفات JSON في النهاية مجرد نصوص، وتنطبق عليها نفس قواعد التعامل مع الملفات.
  • فضّل indent=2 للملفات التي يقرأها البشر كملفات الإعدادات والبيانات التجريبية والبيانات المُصدَّرة. أما في البيانات المرسلة عبر الشبكة فالأفضل تجاهله لأن الحجم المضغوط أهم.
  • اضبط ensure_ascii=False للإخراج بترميز UTF-8 حتى تظل الأسماء العربية أو الحروف اللاتينية المُشكَّلة مقروءة كما هي.
  • تحقّق من صحة البيانات عبر try/except json.JSONDecodeError عند تحليل بيانات قادمة من مصدر خارجي لا تتحكم فيه.

ماذا بعد؟

تتعامل JSON مع البيانات على شكل مفتاح وقيمة. الأداة التالية في نفس الفصل هي CSV، وهي الصيغة الجدولية التي يدعمها بايثون داخليًا، والتي ستجدها خلف معظم ملفات جداول البيانات المُصدَّرة التي ستصادفها.

الأسئلة الشائعة

كيف أحلّل نص JSON في بايثون؟

استخدم json.loads(text) إذا كان لديك نص JSON، أو json.load(file) إذا كنت تقرأ من ملف. الاثنان يُرجعان قاموس بايثون (dict) أو قائمة حسب محتوى JSON. مثال: data = json.loads('{"name": "Rosa"}') ثم data['name'] ستكون قيمتها 'Rosa'.

كيف أحوّل قاموس بايثون إلى JSON؟

الدالة json.dumps(my_dict) تُرجع لك نص JSON جاهز. أما json.dump(my_dict, file) فتكتب مباشرة إلى ملف. ولو أردت إخراجاً منسّقاً وسهل القراءة، استخدم المعامل indent=2 هكذا: json.dumps(data, indent=2).

ما الفرق بين json.loads و json.load؟

loads (بحرف الـ s) تستقبل نصاً (string)، بينما load (بدون s) تستقبل كائن ملف (file object). نفس القاعدة تنطبق على dumps مقابل dump. تذكّر أن حرف الـ s يرمز إلى string — وهذه أسهل طريقة للتمييز بينهما.

كيف أتعامل مع التواريخ والكائنات المخصّصة في JSON؟

JSON لا يدعم نوع تاريخ أصلاً، لذلك الحل المعتاد هو تمرير التاريخ كنص بصيغة ISO-8601 ثم تحليله يدوياً عند القراءة. أما الكائنات المخصّصة فأمامك خياران: إمّا تمرير دالة عبر default= إلى json.dumps تُرجع تمثيلاً متوافقاً مع JSON، أو تحويل الكائن إلى dict يدوياً قبل التسلسل.

تعلّم البرمجة مع Coddy

ابدأ الآن