مسار بايثون· الخطوة 19 من 19

التسلسل و JSON في بايثون: احفظ بياناتك وأرسلها كنص

تعلّم التسلسل في بايثون بوحدة json: حوّل القواميس والقوائم إلى نص بـ dumps، وأعدها بـ loads، واجعل النص مقروءًا بالعربية بدون أخطاء.

أنت تلعب لعبة على الجوال، وتصل إلى المستوى 7 برصيد 950 نقطة. تغلق اللعبة، وفي اليوم التالي تجدها تذكر كل شيء. كيف حفظت اللعبة بياناتك؟ وكيف يرسل تطبيق الطقس درجات الحرارة من الإنترنت إلى جوالك؟ الجواب في هذا الدرس من سلسلة تعلم بايثون: طريقة اسمها التسلسل.

🎯 ماذا ستتعلم؟

بنهاية هذا الدرس ستكون قادرًا على:

  • شرح معنى التسلسل ولماذا نحتاجه في برمجة بايثون.
  • تحويل قاموس أو قائمة إلى نص JSON باستخدام json.dumps().
  • إعادة نص JSON إلى قاموس أو قائمة باستخدام json.loads().
  • جعل نص JSON مرتّبًا ومقروءًا بالعربية.
  • معرفة قواعد JSON التي تغيّر بياناتك بصمت.

🧰 ماذا تحتاج قبل أن تبدأ؟

يجب أن تعرف القواميس و القوائم جيدًا. ويفيدك أن تكون قرأت درس الوحدات والحزم، لأننا سنستورد وحدة جاهزة. كل الأمثلة تعمل في مترجم بايثون في المتصفح. هو محرر بايثون اون لاين بالعربي، فلا تحتاج إلى تحميل بايثون 3 على جهازك.

الفكرة ببساطة

تخيّل أنك تريد إرسال صندوق ألعابك إلى صديق في مدينة أخرى. لا تستطيع إرسال الصندوق نفسه بالبريد، لكنك تستطيع كتابة ورقة تصف كل ما فيه: “3 سيارات، كرة زرقاء، 12 مكعبًا”. صديقك يقرأ الورقة ويبني صندوقًا مطابقًا.

هذا هو التسلسل (serialization): تحويل شيء حيّ في ذاكرة برنامجك، مثل قاموس أو قائمة، إلى نص يمكن حفظه أو إرساله. والعملية العكسية، أي قراءة النص وبناء القاموس من جديد، تسمّى فك التسلسل (deserialization).

الورقة التي نكتبها لها شكل متفق عليه بين كل لغات البرمجة اسمه JSON. النص بصيغة JSON يشبه القاموس في لغة بايثون كثيرًا، ولهذا ستجده سهلًا.

الخطوة 1: من قاموس إلى نص بـ dumps()

نبدأ باستيراد وحدة json المضمّنة في بايثون 3. ثم نمرّر القاموس إلى الدالة json.dumps()، فتعيد لنا نصًّا. الاسم اختصار لعبارة “dump to string” أي “أفرغ في نص”.

import json

player = {"name": "Salem", "level": 7, "score": 950}
saved = json.dumps(player)
print(saved)
print(type(saved))
{"name": "Salem", "level": 7, "score": 950}
<class 'str'>

النتيجة تبدو مثل القاموس تمامًا، لكن انظر إلى السطر الثاني: نوعها str، أي نص عادي. هذا النص يمكنك حفظه في ملف أو إرساله عبر الإنترنت، وهو ما تفعله تطبيقات البايثون كل يوم.

الفرق الوحيد في الشكل أن JSON يستخدم علامات التنصيص المزدوجة " دائمًا، ولا يقبل المفردة '.

الخطوة 2: من نص إلى قاموس بـ loads()

عندما يعود النص إليك، تحتاج إلى قاموس حقيقي لتعمل عليه. الدالة json.loads() تقرأ النص وتبني منه القاموس من جديد. الاسم يعني “load from string” أي “حمّل من نص”.

import json

saved = '{"name": "Salem", "level": 7, "score": 950}'
player = json.loads(saved)
print(type(player))
print(player["name"], "في المستوى", player["level"])
player["score"] = player["score"] + 50
print(player)
<class 'dict'>
Salem في المستوى 7
{'name': 'Salem', 'level': 7, 'score': 1000}

لاحظ أن saved نصّ بين علامتي تنصيص مفردتين، وبداخله علامات مزدوجة. بعد loads() صار عندنا قاموس نقرأ منه بالمفتاح ونعدّله كما تعلّمت. هاتان الدالتان هما أهم أوامر لغة بايثون في هذا الدرس.

🚀 للمتقدمين: وحدة json تعمل مع الملفات أيضًا. الدالة json.dump(data, file) تكتب مباشرة في ملف مفتوح، و json.load(file) تقرأ منه. لاحظ الاسم بدون حرف s. جرّب هذا على جهازك، لأن مترجم المتصفح لا يحتفظ بالملفات بعد إغلاق الصفحة.

الخطوة 3: نص مرتّب ومقروء بالعربية

النص الذي أعطتنا إياه dumps() مضغوط في سطر واحد. مع بيانات أكبر يصعب قراءته. أضف indent=2 لتحصل على أسطر منظّمة بمسافات بادئة.

وهناك مفاجأة عندما تكون البيانات بالعربية. جرّب هذا:

import json

student = {"name": "نورة", "grade": 95}
print(json.dumps(student))
{"name": "\u0646\u0648\u0631\u0629", "grade": 95}

الاسم “نورة” تحوّل إلى رموز غريبة! السبب أن dumps() تكتب الحروف غير الإنجليزية برموز آمنة افتراضيًا. البيانات سليمة، لكن قراءتها صعبة. الحل هو ensure_ascii=False:

import json

student = {"name": "نورة", "grade": 95, "subjects": ["رياضيات", "علوم"]}
print(json.dumps(student, indent=2, ensure_ascii=False))
{
  "name": "نورة",
  "grade": 95,
  "subjects": [
    "رياضيات",
    "علوم"
  ]
}

الآن النص مرتّب ومقروء. هذا الشكل هو ما تراه في ملفات الإعدادات وفي ردود مواقع الإنترنت.

الخطوة 4: بيانات متداخلة

قوة JSON الحقيقية تظهر مع البيانات المتداخلة: قائمة فيها قواميس، وقاموس فيه قوائم. تخيّل جدول ترتيب فريقك في دوري المدرسة:

import json

league = [
    {"team": "الصقور", "points": 12, "wins": [3, 1, 2]},
    {"team": "النجوم", "points": 9, "wins": [2, 2, 0]},
]
text = json.dumps(league, ensure_ascii=False)
print(text)

back = json.loads(text)
print(back[0]["team"], "لها", back[0]["points"], "نقطة")
print(len(back), "فرق")
[{"team": "الصقور", "points": 12, "wins": [3, 1, 2]}, {"team": "النجوم", "points": 9, "wins": [2, 2, 0]}]
الصقور لها 12 نقطة
2 فرق

ذهبت القائمة كلها إلى نص واحد، ثم عادت قائمة فيها قواميس، وكل قاموس فيه قائمة. لم يضع شيء في الطريق.

الخطوة 5: قواعد JSON التي تغيّر بياناتك

JSON ليس بايثون، وله قواعده الخاصة. ثلاثة أشياء تتغيّر بصمت عند الذهاب والعودة، ومن الأفضل أن تعرفها الآن:

import json

data = {1: "أول", "ok": True, "empty": None, "pair": (3, 4)}
text = json.dumps(data, ensure_ascii=False)
print(text)
print(json.loads(text))
{"1": "أول", "ok": true, "empty": null, "pair": [3, 4]}
{'1': 'أول', 'ok': True, 'empty': None, 'pair': [3, 4]}

اقرأ النتيجتين بتمعّن:

  • المفتاح الرقمي 1 صار نصًّا "1"، لأن مفاتيح JSON نصوص دائمًا. بعد العودة تحتاج إلى data["1"] لا data[1].
  • True كُتبت true و None كُتبت null. هذه أسماؤها في JSON، وتعود سليمة إلى بايثون.
  • الصفّ (3, 4) صار قائمة [3, 4]، لأن JSON لا يعرف الصفوف. وبعد العودة يبقى قائمة.

🚀 للمتقدمين: إذا كانت بياناتك ستُقرأ ببرنامج بايثون فقط، فهناك وحدة pickle تحفظ أي كائن بايثون تقريبًا مع نوعه. جرّب pickle.loads(pickle.dumps((3, 4))) وستحصل على صفّ لا قائمة. لكن نتيجتها بايتات لا نص، ولا تفهمها اللغات الأخرى، والأهم أنها غير آمنة مع بيانات من مصدر لا تثق به. لهذا يبقى JSON الخيار الأول.

⚠️ أخطاء شائعة

هذه الأخطاء طبيعية جدًا عند تعلم لغة بايثون، وكل مبرمج وقع فيها مرة. تعرّف عليها لتتجاوزها بسرعة:

1. تمرير قاموس إلى loads() بدل نص

❌ هذا الكود يتوقف بخطأ
import json
player = {"name": "Salem"}
print(json.loads(player))

TypeError: the JSON object must be str, bytes or bytearray, not dict

loads() تريد نصًّا، و dumps() تريد قاموسًا أو قائمة. تذكّر: حرف s يعني string. إذا كان عندك قاموس، فأنت تحتاج إلى dumps():

# ✅ القاموس يذهب إلى dumps لا loads
import json
player = {"name": "Salem"}
print(json.dumps(player))
{"name": "Salem"}

2. كتابة JSON بعلامات تنصيص مفردة

❌ هذا الكود يتوقف بخطأ
import json
text = "{'name': 'Salem'}"
print(json.loads(text))

json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

الرسالة تقول: “أتوقع اسم المفتاح بين علامتي تنصيص مزدوجتين”. JSON يقبل " فقط. اكتب النص الخارجي بعلامات مفردة، وما بداخله بعلامات مزدوجة:

# ✅ علامات مزدوجة داخل JSON
import json
text = '{"name": "Salem"}'
print(json.loads(text))
{'name': 'Salem'}

3. نسيان أن المفاتيح الرقمية تصير نصوصًا

❌ هذا الكود يتوقف بخطأ
import json
scores = json.loads(json.dumps({1: 90, 2: 85}))
print(scores[1])

KeyError: 1

بعد الرحلة إلى JSON والعودة، المفتاح صار "1". اطلبه كنص، أو استخدم مفاتيح نصية من البداية:

# ✅ المفتاح صار نصًّا بعد العودة
import json
scores = json.loads(json.dumps({1: 90, 2: 85}))
print(scores["1"])
90

🧪 جرّب بنفسك

افتح مترجم بايثون وجرّب أكواد بايثون التالية بنفسك. كل تحدٍّ يعطيك كودًا للبداية، وعليك أن تكمله.

التحدي 1: بطاقة اللاعب

عندك قاموس فيه اسمك ولعبتك المفضّلة وأعلى نتيجة. حوّله إلى نص JSON مرتّب بمسافات بادئة وبحروف عربية مقروءة، ثم اطبعه.

import json

me = {"name": "ليلى", "game": "سباق", "best": 4200}
# حوّل القاموس إلى نص مرتّب واطبعه
print(me)
{'name': 'ليلى', 'game': 'سباق', 'best': 4200}
💡 اضغط لرؤية الحل
import json

me = {"name": "ليلى", "game": "سباق", "best": 4200}
card = json.dumps(me, indent=2, ensure_ascii=False)
print(card)
{
  "name": "ليلى",
  "game": "سباق",
  "best": 4200
}

التحدي 2: أضف طالبًا إلى النص

عندك نص JSON فيه درجات طالبين. اكتب دالة add_student() تأخذ النص واسمًا ودرجة، وتعيد نص JSON جديدًا فيه الطالب الثالث. تذكّر: حوّل النص إلى قاموس، أضف، ثم أعده نصًّا.

import json

def add_student(grades_json, name, grade):
    # أكمل الدالة هنا
    return grades_json

grades = '{"Omar": 88, "Hind": 92}'
new_grades = add_student(grades, "Fahd", 79)
print(new_grades)
{"Omar": 88, "Hind": 92}
💡 اضغط لرؤية الحل
import json

def add_student(grades_json, name, grade):
    grades = json.loads(grades_json)
    grades[name] = grade
    return json.dumps(grades)

grades = '{"Omar": 88, "Hind": 92}'
new_grades = add_student(grades, "Fahd", 79)
print(new_grades)
print(json.loads(new_grades)["Fahd"])
{"Omar": 88, "Hind": 92, "Fahd": 79}
79

التحدي 3: مجموع نقاط الدوري

عندك نص JSON فيه قائمة فرق، ولكل فريق قائمة نقاط من ثلاث مباريات. حوّل النص إلى بيانات، ثم مرّ عليها بحلقة for، واطبع اسم كل فريق مع مجموع نقاطه. تذكّر أن الدالة sum() تجمع أرقام أي قائمة.

import json

text = '[{"team": "الصقور", "points": [3, 1, 3]}, {"team": "النجوم", "points": [0, 3, 1]}]'
# حوّل النص واطبع مجموع كل فريق
print(len(text))
82
💡 اضغط لرؤية الحل
import json

text = '[{"team": "الصقور", "points": [3, 1, 3]}, {"team": "النجوم", "points": [0, 3, 1]}]'
league = json.loads(text)
for team in league:
    total = sum(team["points"])
    print(team["team"], ":", total)
الصقور : 7
النجوم : 4

✅ اختبر نفسك

  1. أي دالة تحوّل قاموسًا إلى نص JSON؟

    • أ) json.loads()
    • ب) json.dumps()
    • ج) json.load()
  2. ماذا يصير المفتاح الرقمي 5 بعد dumps() ثم loads()؟

    • أ) يبقى الرقم 5
    • ب) يصير النص "5"
    • ج) يُحذف من القاموس
  3. صح أم خطأ: نص JSON يقبل علامات التنصيص المفردة والمزدوجة.

💡 اضغط لرؤية الإجابات
  1. ب) json.dumps()، فحرف s يعني string، والدالة تعطيك نصًّا.
  2. ب) يصير النص "5"، لأن مفاتيح JSON نصوص دائمًا.
  3. خطأ. JSON يقبل علامات التنصيص المزدوجة " فقط.

📝 الخلاصة

إليك ملخص لغة بايثون في هذا الدرس:

  • التسلسل هو تحويل القواميس والقوائم إلى نص لحفظه أو إرساله، وJSON هو الشكل المتفق عليه.
  • json.dumps() تحوّل البيانات إلى نص، و json.loads() تعيد النص بيانات.
  • indent=2 تجعل النص مرتّبًا، و ensure_ascii=False تُبقي الحروف العربية مقروءة.
  • البيانات المتداخلة، مثل قائمة فيها قواميس، تذهب وتعود بدون مشاكل.
  • مفاتيح JSON نصوص دائمًا، والصفوف تعود قوائم، و True و None تُكتب true و null.

⏭️ الخطوة التالية

هذا آخر درس في سلسلتنا، وقد صار عندك كل ما يحتاجه برنامج بايثون حقيقي. حان وقت المشروع. افتح مترجم بايثون على موقع بايثون اونلاين هذا. ابنِ لعبة أسئلة صغيرة تحفظ اسم اللاعب ونقاطه في قاموس. في نهاية اللعبة حوّل القاموس إلى نص JSON واطبعه. ثم اكتب كودًا يقرأ ذلك النص ويطبع “مرحبًا بعودتك” مع النقاط المحفوظة.

وإذا أردت أن تكمل تعلم لغة بايثون، فارجع إلى الدروس السابقة وجرّب دمج ما فيها. دوال تنظّم الكود، وحلقات تكرّر، وقواميس تحفظ، وJSON يرسل. هكذا تُبنى تطبيقات البايثون التي تستخدمها كل يوم، خطوة بعد خطوة، وأنت الآن تعرف كل خطوة منها.