التسلسل
درس 7 من 8
7التسلسل (Serialization): JSON، Pickle، CSV، و XML
الصورة الكبيرةكيف تحوّل كائن بايثون في الذاكرة إلى صيغة قابلة للحفظ في ملف أو الإرسال عبر الشبكة، وكيف تُعيد بناءه بالضبط كما كان.
ماذا تشاهد في الرسم: القاموس في الذاكرة لا يُرسل كما هو؛ dumps تحوّله نصًا يُحفظ في ملف أو يُرسل، وloads تعيده قاموسًا في الطرف الآخر.
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
التسلسل مثل تفكيك قطعة أثاث لتضعها في صندوق وتشحنها، ثم تركيبها كما كانت في البيت الجديد. البيانات في ذاكرة البرنامج «أثاث مركّب»، ولكي تحفظها في ملف أو ترسلها عبر الإنترنت تحوّلها إلى نص مرتب (مثل JSON)، ثم يعيد البرنامج الآخر تركيبها.
json.dumps/json.loads تحوّل القواميس والقوائم إلى نص قابل للتبادل بين اللغات، وpickle يحفظ أي كائن بايثون لكنه غير آمن مع بيانات لا تثق بها. وcsv للجداول وxml.etree للوثائق الهرمية. استخدم ensure_ascii=False ليبقى النص العربي مقروءًا.
الأساسيات المطلوبة
| المفهوم | لماذا يهمّك هنا |
|---|---|
| التعامل مع الملفات (درس الملفات) | كل عملية تسلسل تنتهي بكتابة النتيجة في ملف أو قراءتها منه. |
| الأصناف والكائنات (درس الأصناف والكائنات) | Pickle يحتاج فهم بنية الكائن (خصائصه) لحفظه واستعادته بالضبط. |
المفاهيم الأساسية
التسلسل (Serialization) هو تحويل بنية بيانات أو كائن موجود في ذاكرة البرنامج إلى تسلسل من البايتات أو نص يمكن تخزينه أو نقله. فك التسلسل (Deserialization) هو العملية العكسية: إعادة بناء الكائن الأصلي من تلك البايتات.
| الصيغة | نوعها | تقرأها لغات أخرى؟ | متى تُستخدم |
|---|---|---|---|
| JSON | نص (قابل للقراءة البشرية) | نعم، معيار عالمي مشترك | تبادل البيانات بين أنظمة مختلفة، إعدادات، واجهات برمجية (APIs) |
| Pickle | ثنائي (binary) | لا، خاص ببايثون فقط | حفظ كائنات بايثون معقّدة (أصناف مخصّصة) داخل نظامك الخاص فقط |
| CSV | نص (جداول بسيطة) | نعم، يفتحه أي برنامج جداول | بيانات جدولية بسيطة (صفوف وأعمدة) |
| XML | نص (هيكل شجري) | نعم، معيار قديم وواسع الانتشار | بيانات هرمية معقّدة، أنظمة قديمة (Legacy) ما زالت تتطلبه |
الرسم 18: رحلة التسلسل كاملة: ذهابًا (serialize) وعودة (deserialize)، الهدف أن يكون OBJ2 مطابقًا تمامًا لـOBJ.
pickle.load() أبدًا على بيانات مصدرها غير موثوق (ملف من الإنترنت، مُدخل من مستخدم مجهول)، صيغة Pickle يمكن أن تحتوي كودًا قابلًا للتنفيذ عند فك تسلسلها، وهذا يُستخدم فعليًا كثغرة أمنية. استخدم JSON للبيانات غير الموثوقة دائمًا.
أربع صيغ، أربعة أمثلة أصلية
1JSON: إعدادات لعبة بسيطة
import json
settings = {"player_name": "نورة", "volume": 75, "difficulty": "صعب"}
with open("settings.json", "w", encoding="utf-8") as f:
json.dump(settings, f, ensure_ascii=False, indent=2)
with open("settings.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["difficulty"]) # صعب — نفس القيمة بالضبط
2Pickle: حفظ كائن مخصّص (ملف حفظ لعبة)
import pickle
class GameSave:
"""يمثّل تقدّم لاعب داخل لعبة."""
def __init__(self, level, score, inventory):
self.level = level
self.score = score
self.inventory = inventory
def serialize(self, filename):
with open(filename, "wb") as f:
pickle.dump(self, f)
@classmethod
def deserialize(cls, filename):
with open(filename, "rb") as f:
return pickle.load(f)
save = GameSave(level=7, score=3200, inventory=["درع", "مفتاح ذهبي"])
save.serialize("save1.pkl")
restored = GameSave.deserialize("save1.pkl")
print(restored.level, restored.inventory) # 7 ['درع', 'مفتاح ذهبي']
لاحظ أن pickle.load() لم يحتَج منك أن تخبره أي صنف يُعيد بناءه، لأن Pickle يخزّن مع البيانات نفسها مرجعًا لاسم الصنف ووحدته بالإضافة إلى لقطة من __dict__ الكائن، فيستورد الصنف تلقائيًا عند الاستعادة ويُعيد بناء كائن جديد بنفس الحالة بالضبط. هذا بالضبط مصدر الخطر الأمني المذكور أعلاه: استعادة بيانات Pickle تعني تنفيذ كود استيراد وبناء كائنات بثقة كاملة بما تحتويه.
3CSV إلى JSON: تحويل جدول نتائج
import csv
import json
## scores.csv يحتوي: name,points\nسارة,88\nعمر,95
with open("scores.csv", "r", encoding="utf-8") as csv_file:
reader = csv.DictReader(csv_file)
rows = list(reader)
with open("scores.json", "w", encoding="utf-8") as json_file:
json.dump(rows, json_file, ensure_ascii=False, indent=2)
## النتيجة: [{"name": "سارة", "points": "88"}, {"name": "عمر", "points": "95"}]
4XML: قراءة قائمة مخزون بسيطة
import xml.etree.ElementTree as ET
## inventory.xml:
## <inventory>
## <item name="سيف" quantity="2"/>
## <item name="ترس" quantity="1"/>
## </inventory>
tree = ET.parse("inventory.xml")
root = tree.getroot()
for item in root.findall("item"):
print(item.get("name"), "->", item.get("quantity"))
"wb"/"rb". JSON يُنتج نصًا عاديًا قابلًا للقراءة، فيكفي الوضع النصي الافتراضي "w"/"r".
مثال محلول
json.dump(settings, f) يكتب نصًّا تفهمه كل اللغات، بينما Pickle خاص ببايثون وخطر إن جاء من مصدر لا تثق به.خرافة مقابل حقيقة
| الخرافة | الحقيقة |
|---|---|
| JSON و Pickle يؤديان نفس الغرض تقريبًا | JSON محدود بأنواع بيانات بسيطة (نص، رقم، قائمة، قاموس) ولا يحفظ أصنافًا مخصّصة مباشرة؛ Pickle يحفظ أي كائن بايثون تقريبًا كما هو. |
| CSV مناسب لأي بيانات جدولية بدون استثناء | CSV يتعامل بصعوبة مع البيانات المتداخلة (قائمة داخل خلية) أو النصوص التي تحتوي فواصل، JSON غالبًا أنسب للبيانات المعقّدة. |
| XML تقنية قديمة لا فائدة من تعلّمها | أنظمة مؤسسية كبيرة (تعليم، حكومة، تأمين) ما زالت تعتمد XML بكثافة لتبادل البيانات حتى اليوم. |
أين تُستخدم هذه الفكرة فعليًا؟
واجهات برمجية (APIs)
معظم واجهات الويب ترسل وتستقبل البيانات بصيغة JSON.
حفظ تقدّم البرامج
حفظ حالة برنامج كامل (كائنات معقّدة) بـPickle لاستئنافه لاحقًا.
تحليل البيانات
تحويل ملفات CSV من جدول بيانات إلى JSON لمعالجتها برمجيًا.
تكامل الأنظمة القديمة
أنظمة الشركات الكبيرة والحكومية غالبًا تتبادل البيانات عبر XML.
جرّب بنفسك
تريد إرسال بيانات لبرنامج مكتوب بلغة أخرى. أي صيغة لا تصلح؟
Pickle صيغة ثنائية خاصة ببايثون، ولا تفهمها اللغات الأخرى، وفتحها من مصدر مجهول خطر.
بطاقات مراجعة سريعة
اختبر فهمك
1. لو أردت إرسال بيانات لخدمة ويب مكتوبة بلغة أخرى (جافاسكريبت مثلاً)، أي صيغة تختار ولماذا؟
JSON، لأنه معيار مشترك تقرأه كل اللغات، بعكس Pickle المحصور ببايثون فقط.
2. لماذا يحتاج Pickle ميثود classmethod لإعادة بناء الكائن بينما JSON لا يحتاج؟
Pickle يعيد بناء الكائن كاملاً تلقائيًا بما فيه نوعه وخصائصه. استخدام classmethod هنا مجرد تنظيم كود مناسب (واجهة واضحة)، وليس حاجة تقنية إلزامية من Pickle نفسه.
3. ما أكبر تحدٍ عند تحويل CSV إلى JSON إذا كان عمود يحتوي قائمة قيم مفصولة بفاصلة منقوطة؟
CSV يقرأ كل خلية كنص خام بشكل افتراضي، فستحتاج معالجة إضافية (مثل .split(";")) لتحويل ذلك النص إلى قائمة JSON فعلية بدل تركه نصًا واحدًا طويلاً.
مصادر هذا الدرس
مرتّبة بالنوع. ابدأ بالتوثيق الرسمي إذا تبي المرجع الدقيق، وبالمقال أو الفيديو إذا تبي الشرح أولًا.
توثيق رسمي3
خلّصت الدرس؟
سجّل الدخول ليُحفظ تقدّمك.