عمليات Dictionary في Python: التكرار والدمج والقواميس المتداخلة | أساسيات بايثون 18

عمليات Dictionary في Python: التكرار والدمج والقواميس المتداخلة

إذا كنت تعرف بالفعل ما هو Dictionary وكيف تنشئ قاموسًا وتصل إلى قيمة باستخدام المفتاح، فالخطوة التالية هي تعلّم العمليات العملية على القواميس في Python: كيف تمر على المفاتيح والقيم، تحدّث القاموس، تضيف قيمة افتراضية، تدمج قاموسين، تتعامل مع القواميس المتداخلة، تنسخ القاموس، وتبني قاموسًا جديدًا باستخدام dict comprehension.

هذا الدرس لا يعيد شرح Dictionary من البداية. إذا كنت ما زلت تتعلم إنشاء القاموس والوصول إلى القيم وget()، فابدأ من شرح Dictionary في Python للمبتدئين، ثم عد إلى هنا لتطبيق العمليات التالية.

{alertInfo} الفكرة ببساطة: سنركز هنا على ما تفعله بعد إنشاء القاموس: items() للتكرار، update() للتحديث، setdefault() للقيم الافتراضية، | للدمج، والقواميس المتداخلة والنسخ وDictionary Comprehension.

{getToc} $title={محتوى المقال}

مراجعة سريعة قبل عمليات Dictionary

يكفي أن تتذكر أن القاموس يربط كل key بقيمة value. لن نعيد هنا شرح الأقواس المعقوفة أو الوصول الأساسي بالتفصيل.

user = {
    "name": "Ali",
    "role": "editor"
}

print(user["name"])

إذا فهمت المثال السابق، فأنت جاهز للعمليات العملية في بقية الدرس.

شرح فكرة Dictionary في Python وكيف يخزن البيانات على شكل مفتاح وقيمة

التكرار على Dictionary باستخدام items()

عندما تحتاج إلى المفتاح والقيمة معًا داخل حلقة، استخدم items(). هذه من أكثر عمليات Dictionary فائدة في البرامج العملية.

student = {
    "name": "Sara",
    "age": 19,
    "grade": "A"
}

for key, value in student.items():
    print(key, value)

في كل دورة تعيد items() زوجًا من key وvalue. وإذا كنت تحتاج المفاتيح فقط، يمكنك المرور مباشرة على القاموس باستخدام for key in student.

مثال يوضح الوصول إلى قيمة داخل Dictionary في بايثون باستخدام المفتاح key

تحديث Dictionary باستخدام update()

تستخدم update() لإضافة مفاتيح جديدة أو تحديث قيم مفاتيح موجودة. إذا كان المفتاح موجودًا، تُستبدل قيمته بالقيمة الجديدة.

profile = {
    "name": "Ali",
    "city": "Aden"
}

profile.update({
    "city": "Sanaa",
    "active": True
})

print(profile)
{'name': 'Ali', 'city': 'Sanaa', 'active': True}

انتبه إلى أن update() يعدّل القاموس نفسه ولا ينشئ نسخة جديدة، كما أنها تعيد None.

شرح إضافة وتعديل وحذف عناصر Dictionary في بايثون باستخدام المفاتيح

استخدام setdefault() عند الحاجة إلى قيمة افتراضية

تستخدم setdefault(key, default) عندما تريد الحصول على قيمة مفتاح، وإذا لم يكن المفتاح موجودًا تريد إضافته بالقيمة الافتراضية في العملية نفسها. إذا كان المفتاح موجودًا أصلًا، تعيد قيمته الحالية ولا تستبدلها.

groups = {}

groups.setdefault("python", []).append("Ali")
groups.setdefault("python", []).append("Sara")
groups.setdefault("web", []).append("Omar")

print(groups)
{'python': ['Ali', 'Sara'], 'web': ['Omar']}

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

{alertWarning} مهم: setdefault() لا تكتفي بالقراءة؛ قد تضيف مفتاحًا جديدًا إلى القاموس. إذا كنت تريد قراءة قيمة فقط دون تعديل القاموس، استخدم get().

دمج Dictionary في Python

في Python 3.9 وما بعده يمكنك دمج قاموسين باستخدام العامل |. النتيجة تكون قاموسًا جديدًا، وإذا تكرر المفتاح فالقيمة الموجودة في القاموس الموجود على اليمين هي التي تفوز.

defaults = {
    "theme": "light",
    "language": "ar"
}

user_settings = {
    "theme": "dark",
    "font_size": 18
}

settings = defaults | user_settings

print(settings)
{'theme': 'dark', 'language': 'ar', 'font_size': 18}

يمكنك أيضًا استخدام فك القواميس ** لإنشاء قاموس جديد:

settings = {**defaults, **user_settings}
print(settings)

أما إذا أردت تعديل القاموس الأول نفسه، فاستخدم defaults.update(user_settings). الفرق مهم: العامل | ينشئ قاموسًا جديدًا، بينما update() يعدّل القاموس الموجود.

القواميس المتداخلة Nested Dictionaries

القاموس المتداخل هو Dictionary يحتوي داخل إحدى قيمه على Dictionary آخر. هذا الشكل مناسب لبيانات مثل الطلاب والمنتجات والإعدادات التي تحتوي مجموعات فرعية من الخصائص.

students = {
    101: {
        "name": "Ali",
        "grades": {"python": 90, "sql": 82}
    },
    102: {
        "name": "Sara",
        "grades": {"python": 95, "sql": 88}
    }
}

print(students[102]["grades"]["python"])
95

للوصول إلى قيمة متداخلة، تتبع المفاتيح مستوى بعد مستوى. ويمكنك التكرار على القاموس الخارجي ثم قراءة القيم الداخلية:

for student_id, data in students.items():
    python_grade = data["grades"]["python"]
    print(student_id, data["name"], python_grade)
101 Ali 90
102 Sara 95
ملخص عمليات Dictionary في Python مثل items وupdate وsetdefault والدمج

إذا أصبحت البنية عميقة جدًا، لا تجعل الوصول بسلسلة طويلة من الأقواس هو الحل الوحيد؛ نظّم البيانات أو استخدم دوال صغيرة واضحة للوصول إلى الأجزاء التي تحتاجها.

نسخ Dictionary: الفرق بين = وcopy()

كتابة copy_dict = original لا تنشئ قاموسًا مستقلًا، بل تجعل الاسمين يشيران إلى الكائن نفسه. أما dict.copy() فتنشئ نسخة سطحية shallow copy.

original = {
    "name": "Ali",
    "settings": {"theme": "dark"}
}

shallow = original.copy()
shallow["name"] = "Sara"
shallow["settings"]["theme"] = "light"

print(original["name"])
print(original["settings"]["theme"])
Ali
light

تغيير المفتاح العلوي name لم يؤثر في الأصل، لكن تعديل القاموس المتداخل settings ظهر في الأصل أيضًا؛ لأن النسخة السطحية لا تنسخ الكائنات المتداخلة بشكل مستقل.

إذا احتجت نسخة مستقلة لبنية متداخلة، استخدم deepcopy() عند الحاجة:

from copy import deepcopy

independent = deepcopy(original)
independent["settings"]["theme"] = "blue"

print(original["settings"]["theme"])
print(independent["settings"]["theme"])
light
blue

إنشاء Dictionary باستخدام Dict Comprehension

يمكنك إنشاء قاموس جديد بصيغة مختصرة تشبه List Comprehension. وهي مناسبة عندما تريد تحويل المفاتيح والقيم أو الاحتفاظ بالعناصر التي تحقق شرطًا.

prices = {
    "book": 10,
    "pen": 3,
    "bag": 25,
    "mouse": 18
}

expensive = {
    name: price
    for name, price in prices.items()
    if price >= 15
}

print(expensive)
{'bag': 25, 'mouse': 18}

الصيغة العامة هي:

{key_expression: value_expression for item in iterable if condition}

تحويل بيانات List of Dictionaries إلى Dictionary مفهرس بالـ id

في البيانات العملية قد تبدأ بقائمة من القواميس، ثم تكتشف أنك تبحث كثيرًا حسب id. يمكنك بناء قاموس جديد يجعل id هو المفتاح، وبذلك يصبح الوصول المباشر أوضح.

products = [
    {"id": 101, "name": "Book", "price": 5},
    {"id": 102, "name": "Pen", "price": 2},
    {"id": 103, "name": "Bag", "price": 20}
]

products_by_id = {
    product["id"]: product
    for product in products
}

print(products_by_id[103]["name"])
Bag

إذا كان هدفك الأساسي هو البحث داخل قائمة قواميس حسب id أو name دون تغيير شكل البيانات، راجع أيضًا البحث داخل List of Dictionaries في Python.

لا تعدّل حجم Dictionary أثناء التكرار عليه مباشرة

إضافة مفاتيح أو حذفها أثناء المرور مباشرة على القاموس قد يؤدي إلى RuntimeError: dictionary changed size during iteration. المثال التالي غير آمن:

data = {"a": 1, "b": 2, "c": 3}

for key in data:
    if data[key] < 3:
        del data[key]

إذا كنت تحتاج إلى حذف مفاتيح أثناء التكرار، مرّ على نسخة من المفاتيح:

data = {"a": 1, "b": 2, "c": 3}

for key in list(data):
    if data[key] < 3:
        del data[key]

print(data)
{'c': 3}

جدول سريع لاختيار عملية Dictionary المناسبة

المطلوب الأداة المناسبة ملاحظة
التكرار على المفتاح والقيمة items() مناسبة مع for key, value in data.items().
تحديث مفاتيح أو إضافة أخرى update() تعدّل القاموس نفسه وتستبدل القيمة عند تكرار المفتاح.
إضافة قيمة افتراضية إذا غاب المفتاح setdefault() قد تغيّر القاموس بإضافة المفتاح.
دمج قاموسين في قاموس جديد d1 | d2 متاحة من Python 3.9، وقيم القاموس الأيمن تتقدم عند التعارض.
نسخ القاموس copy() نسخة سطحية؛ انتبه للكائنات المتداخلة.
إنشاء قاموس بتحويل أو شرط Dict Comprehension مناسبة للتحويل والفلترة.
تمثيل بيانات لها مستويات Nested Dictionary مثل طالب يحتوي قاموس درجات داخليًا.

مثال عملي يجمع أكثر من عملية

لنفترض أن لديك إعدادات افتراضية وإعدادات اختارها المستخدم. يمكنك دمجها، ثم المرور على الإعدادات النهائية باستخدام items():

defaults = {
    "language": "ar",
    "theme": "light",
    "notifications": {
        "email": True,
        "push": True
    }
}

user = {
    "theme": "dark"
}

config = defaults | user

for key, value in config.items():
    print(key, value)

هنا ينتصر "dark" على "light" لأن قاموس المستخدم جاء على اليمين. لكن لاحظ أن دمج القواميس بـ| دمج سطحي أيضًا؛ إذا كان القاموسان يحتويان المفتاح نفسه وقيمته قاموس متداخل، فالقيمة اليمنى تستبدل اليسرى بالكامل لذلك المفتاح.

أخطاء شائعة في عمليات Dictionary

  • استخدام update() وانتظار قاموس جديد: الدالة تعدّل القاموس وتعيد None.
  • الخلط بين get() وsetdefault(): الأولى للقراءة الآمنة، والثانية قد تضيف المفتاح.
  • نسيان أولوية القاموس الأيمن عند الدمج: في d1 | d2 تفوز قيمة d2 عند تكرار المفتاح.
  • اعتبار copy() نسخة عميقة: هي نسخة سطحية، لذلك القوائم والقواميس المتداخلة قد تبقى مشتركة.
  • تغيير حجم القاموس أثناء التكرار: أضف أو احذف المفاتيح خارج الحلقة، أو مرّ على نسخة مناسبة.

الخلاصة

  • استخدم items() عندما تحتاج المفتاح والقيمة داخل الحلقة.
  • استخدم update() عندما تريد تعديل القاموس الموجود.
  • استخدم setdefault() عندما تريد قيمة موجودة أو إنشاء قيمة افتراضية عند غياب المفتاح.
  • استخدم | لإنشاء قاموس مدمج جديد في Python 3.9 وما بعده.
  • تعامل مع Nested Dictionaries مستوى بمستوى، ولا تجعل البنية أعمق من اللازم.
  • copy() تنشئ shallow copy، بينما البنى المتداخلة المستقلة قد تحتاج deepcopy().
  • استخدم Dict Comprehension للتحويل أو الفلترة أو إعادة فهرسة البيانات.
{alertSuccess} القاعدة العملية: تعلّم العملية حسب الهدف، لا حسب اسم الدالة: تكرار → items()، تحديث → update()، قيمة افتراضية → setdefault()، دمج → |، تحويل → Dict Comprehension.

مصادر رسمية للتوسع

أسئلة شائعة

كيف أكرر على key وvalue في Dictionary؟

استخدم for key, value in data.items():. هذه هي الطريقة المباشرة عندما تحتاج المفتاح والقيمة معًا.

ما الفرق بين update() ودمج القواميس باستخدام |؟

update() تعدّل القاموس الموجود، بينما d1 | d2 تنشئ قاموسًا جديدًا. عند تكرار المفتاح تستخدم الطريقتان قيمة القاموس الثاني.

متى أستخدم setdefault()؟

استخدمها عندما تحتاج إلى قيمة المفتاح، وتريد في الوقت نفسه إضافة قيمة افتراضية إذا لم يكن المفتاح موجودًا. وهي مفيدة في سيناريوهات التجميع.

هل copy() تنسخ Nested Dictionary بالكامل؟

لا. copy() تنشئ shallow copy، لذلك القواميس أو القوائم المتداخلة تبقى مراجع مشتركة. استخدم deepcopy() عندما تحتاج نسخة مستقلة من البنية المتداخلة.

ما فائدة Dict Comprehension؟

تسمح بإنشاء Dictionary جديد من iterable مع تحويل المفاتيح أو القيم وإضافة شرط للفلترة في صيغة مختصرة.

إرسال تعليق

أحدث أقدم