الفصل السابع: هياكل البيانات – تنظيم معلوماتك
مقدمة الفصل
في الفصول السابقة، كانت متغيراتنا تخزن قيمة واحدة فقط، مثل اسم واحد أو رقم واحد. لكن فكر في العالم الحقيقي: قائمة التسوق تحتوي على عدة أصناف، بطاقة الاتصال في هاتفك تحتوي على عدة معلومات (الاسم، الرقم، البريد الإلكتروني)، وقائمة الطلاب في فصل دراسي تحتوي على عدة طلاب.
لتمثيل هذه المجموعات من البيانات المترابطة، نحتاج إلى أدوات أكثر قوة من مجرد متغير بسيط. هذه الأدوات تسمى هياكل البيانات (Data Structures). هي طرق متخصصة لتنظيم وتخزين مجموعات البيانات لتسهيل الوصول إليها وإدارتها بكفاءة.
في هذا الفصل، سنتعمق في أهم ثلاثة هياكل بيانات أساسية في بايثون، والتي ستستخدمها في كل مشاريعك تقريبًا:
- القوائم (Lists): مثل قائمة تسوق يمكنك تعديلها باستمرار.
- المجموعات الثابتة (Tuples): مثل إحداثيات ثابتة على خريطة لا يمكن تغييرها.
- القواميس (Dictionaries): مثل بطاقة اتصال في هاتفك، تربط بين معلومة (الاسم) وبياناتها (الرقم).
1. القوائم (Lists): حاويتك المرنة
القائمة هي أكثر هياكل البيانات مرونة وشيوعًا في بايثون. إنها بالضبط مثل قائمة التسوق التي تكتبها على ورقة: يمكنك إضافة عناصر جديدة في أي وقت، شطب عناصر قديمة، أو تغيير رأيك بشأن عنصر موجود.
خصائص القائمة الرئيسية:
- مرتبة (Ordered): العناصر تحافظ على ترتيبها الذي أُضيفت به. العنصر الأول يبقى الأول، والعنصر الأخير يبقى الأخير.
- قابلة للتعديل (Mutable): هذه هي الميزة الأهم. “Mutable” تعني أنه يمكنك تغيير محتويات القائمة بعد إنشائها (إضافة، حذف، تعديل).
- تسمح بالتكرار: يمكنك إضافة نفس العنصر أكثر من مرة (مثل إضافة “حليب” مرتين في قائمة التسوق).
إنشاء قائمة
الوصف:
لإنشاء قائمة، نضع العناصر التي نريدها بين قوسين مربعين []
ونفصل بينها بفاصلة ,
. يمكن أن تحتوي القائمة على أي نوع من البيانات، أو حتى خليط منها.
# قائمة من النصوص لتخزين أسماء المهام
tasks = ["قراءة كتاب", "حل التمارين", "الذهاب للتسوق"]
# قائمة من الأعداد الصحيحة
grades = [88, 92, 75, 95]
# قائمة فارغة يمكننا إضافة عناصر إليها لاحقًا
shopping_list = []
print(tasks)
print(grades)
الشرح:
أنشأنا ثلاث قوائم. tasks
و grades
تحتويان على بيانات من نفس النوع. shopping_list
هي قائمة فارغة جاهزة لاستقبال عناصر جديدة.
العمليات الأساسية على القوائم
الوصول إلى العناصر (Indexing)
الوصف:
للوصول إلى عنصر واحد محدد في القائمة، نستخدم فهرسه (index)، وهو رقمه الترتيبي. تذكر دائمًا أن الفهرسة في بايثون تبدأ من الصفر 0
.
# تعريف قائمة بلغات البرمجة
programming_languages = ["Python", "JavaScript", "Java", "C++"]
# الوصول للعنصر الأول (فهرس 0)
first_language = programming_languages[0]
print(f"العنصر الأول: {first_language}")
# الوصول للعنصر الأخير باستخدام الفهرسة السلبية (-1)
last_language = programming_languages[-1]
print(f"العنصر الأخير: {last_language}")
الشرح:
نستخدم الأقواس المربعة []
بعد اسم القائمة ونضع بداخلها رقم الفهرس. programming_languages[0]
يعطينا العنصر في المكان الأول. الفهرسة السلبية مفيدة جدًا للوصول إلى نهاية القائمة دون الحاجة لمعرفة طولها.
اقتطاع أجزاء من القائمة (Slicing)
الوصف:
إذا أردت الحصول على جزء من القائمة (قائمة فرعية) بدلاً من عنصر واحد، يمكنك استخدام الاقتطاع (Slicing). الصيغة هي [start:end]
، حيث تأخذ كل العناصر بداية من فهرس start
وحتى ما قبل فهرس end
.
letters = ['a', 'b', 'c', 'd', 'e', 'f']
# اقتطاع من الفهرس 1 إلى 3 (لا يشمل الفهرس 4)
sub_list = letters[1:4]
print(f"قائمة فرعية: {sub_list}")
# اقتطاع من البداية إلى الفهرس 2
first_three = letters[:3]
print(f"أول ثلاثة عناصر: {first_three}")
الشرح:
letters[1:4]
أعطتنا العناصر في الفهارس 1, 2, 3. لاحظ أن العنصر في فهرس 4 لم يتم تضمينه. letters[:3]
هي طريقة مختصرة لـ letters[0:3]
.
تعديل عنصر في القائمة
الوصف: بما أن القوائم قابلة للتعديل (mutable)، يمكنك تغيير قيمة أي عنصر ببساطة عن طريق الوصول إليه عبر فهرسه وإسناد قيمة جديدة له.
# تعريف قائمة من الأرقام
numbers = [1, 2, 3, 4, 5]
print(f"القائمة الأصلية: {numbers}")
# تغيير قيمة العنصر الثاني (فهرس 1)
numbers[1] = 200
print(f"القائمة المعدلة: {numbers}")
الشرح:
في السطر الرابع، قمنا باستبدال القيمة 2
بالقيمة الجديدة 200
، وتغيرت القائمة بشكل دائم.
أهم دوال القوائم (List Methods)
الدوال (Methods) هي إجراءات جاهزة يمكن تنفيذها على القائمة لتعديلها أو الحصول على معلومات منها.
إضافة عنصر إلى نهاية القائمة: .append()
الوصف:
الدالة append
هي الطريقة الأكثر شيوعًا لإضافة عنصر جديد. تقوم دائمًا بإضافة العنصر إلى آخر مكان في القائمة.
fruits = ["تفاح", "موز"]
print(f"القائمة قبل الإضافة: {fruits}")
# إضافة "برتقال" إلى نهاية القائمة
fruits.append("برتقال")
print(f"القائمة بعد الإضافة: {fruits}")
الشرح:
بعد استخدام append
، أصبحت القائمة تحتوي على ثلاثة عناصر، و”برتقال” هو العنصر الأخير.
إدراج عنصر في مكان محدد: .insert()
الوصف:
إذا أردت إضافة عنصر في مكان معين وليس في النهاية، استخدم insert
. تأخذ هذه الدالة معاملين: الفهرس الذي تريد الإدراج فيه، والقيمة التي تريد إدراجها.
my_list = ["a", "b", "d"]
print(f"القائمة الأصلية: {my_list}")
# إدراج الحرف "c" في الفهرس 2
my_list.insert(2, "c")
print(f"القائمة بعد الإدراج: {my_list}")
الشرح:
تم إدراج "c"
في المكان الذي فهرسه 2
، وتم إزاحة العنصر d
والعناصر التي تليه إلى اليمين.
حذف عنصر حسب القيمة: .remove()
الوصف:
إذا كنت تعرف قيمة العنصر الذي تريد حذفه ولكن لا تعرف فهرسه، استخدم remove
. ستبحث هذه الدالة عن أول ظهور للعنصر المحدد وتقوم بحذفه.
my_list = ["a", "x", "b", "x"]
print(f"القائمة الأصلية: {my_list}")
# حذف أول ظهور للحرف "x"
my_list.remove("x")
print(f"القائمة بعد الحذف: {my_list}")
الشرح:
تم حذف الحرف "x"
الأول فقط، بينما بقي الحرف "x"
الثاني في القائمة.
حذف عنصر حسب الفهرس: .pop()
الوصف:
الدالة pop
تحذف العنصر الموجود في فهرس معين، ولكنها أيضًا تعيد لك قيمة هذا العنصر المحذوف لتتمكن من استخدامه. إذا لم تحدد أي فهرس، ستقوم بحذف وإرجاع العنصر الأخير في القائمة.
my_list = ["a", "b", "c"]
print(f"القائمة الأصلية: {my_list}")
# حذف وإرجاع آخر عنصر
last_item = my_list.pop()
print(f"العنصر المحذوف: {last_item}")
print(f"القائمة بعد الحذف: {my_list}")
الشرح:
pop
حذفت العنصر "c"
من القائمة، وقمنا بتخزين هذه القيمة المحذوفة في المتغير last_item
.
عمليات مفيدة أخرى
معرفة طول القائمة: len()
الوصف:
len()
هي دالة عامة (ليست method) تستخدم لمعرفة عدد العناصر الموجودة في أي حاوية، بما في ذلك القوائم.
numbers = [10, 20, 30, 40, 50]
count = len(numbers)
print(f"القائمة تحتوي على {count} عناصر.")
التحقق من وجود عنصر: in
الوصف:
المعامل in
هو أداة بسيطة وقوية للتحقق مما إذا كان عنصر معين موجودًا في القائمة أم لا. يعيد True
أو False
.
languages = ["Python", "JavaScript", "Java"]
if "Python" in languages:
print("نعم، بايثون هي إحدى اللغات المتاحة.")
2. المجموعات الثابتة (Tuples)
المجموعة الثابتة، أو الـ tuple
، تشبه القائمة إلى حد كبير. إنها مجموعة مرتبة من العناصر. لكن فرقها الجوهري هو أنها غير قابلة للتعديل (Immutable). بمجرد إنشائها، لا يمكنك تغيير أو إضافة أو حذف أي شيء من محتوياتها.
لماذا نحتاجها؟ فكر فيها كصندوق زجاجي مغلق. يمكنك أن ترى ما بداخله، لكن لا يمكنك تغيير محتوياته. هذا مفيد جدًا للبيانات التي يجب أن تبقى ثابتة وآمنة من أي تغيير عرضي، مثل إعدادات برنامج أو إحداثيات جغرافية.
إنشاء مجموعة ثابتة
الوصف:
لإنشاء tuple
، نستخدم الأقواس العادية ()
بدلاً من المربعة.
# مجموعة ثابتة من الإحداثيات
coordinates = (10.0, 20.5)
# مجموعة ثابتة من الألوان الأساسية
primary_colors = ("أحمر", "أخضر", "أزرق")
# الوصول للعناصر بنفس طريقة القوائم
print(f"اللون الأول: {primary_colors[0]}")
# السطر التالي سيسبب خطأ TypeError لأن الـ tuple غير قابل للتعديل
# primary_colors[0] = "أصفر"
الشرح:
الوصول للعناصر والفهرسة والاقتطاع تعمل تمامًا كما في القوائم. لكن أي محاولة لتغيير عنصر ستؤدي إلى توقف البرنامج مع خطأ TypeError
.
تفكيك الـ Tuple (Tuple Unpacking)
الوصف:
هي ميزة أنيقة في بايثون تسمح لك بإسناد كل قيمة من قيم الـ tuple
إلى متغير منفصل في سطر واحد فقط.
point = (150, 300)
# سيتم إسناد 150 إلى x و 300 إلى y
x, y = point
print(f"الإحداثي السيني: {x}")
print(f"الإحداثي الصادي: {y}")
الشرح:
هذا الأسلوب أكثر اختصارًا وأناقة من كتابة x = point[0]
و y = point[1]
.
3. القواميس (Dictionaries)
تخيل قاموسًا لغويًا حقيقيًا. أنت لا تبحث عن الكلمة الخامسة في القاموس؛ بل تبحث عن كلمة محددة (المفتاح) لتحصل على تعريفها (القيمة). القواميس في بايثون تعمل بنفس الطريقة تمامًا.
خصائص القاموس:
- أزواج المفتاح-القيمة (Key-Value Pairs): كل عنصر هو زوج مكون من مفتاح فريد وقيمة مرتبطة به.
- قابل للتعديل (Mutable): يمكنك إضافة وتعديل وحذف الأزواج.
- المفاتيح فريدة (Unique Keys): لا يمكن أن يتكرر نفس المفتاح في القاموس.
- مرتبة حسب الإضافة (في بايثون 3.7+): في الإصدارات الحديثة، تحافظ القواميس على ترتيب العناصر كما تم إضافتها.
إنشاء قاموس
الوصف:
لإنشاء قاموس، نستخدم الأقواس المعقوفة {}
. كل عنصر نكتبه على شكل key: value
.
# قاموس يمثل معلومات موظف
employee = {
"name": "علياء",
"job_title": "مهندسة برمجيات",
"years_experience": 5,
"is_remote": True
}
print(employee)
العمليات الأساسية على القواميس
الوصول إلى قيمة
الوصف:
للوصول إلى قيمة، نستخدم الأقواس المربعة []
ونضع بداخلها المفتاح المرتبط بتلك القيمة.
# الوصول إلى المسمى الوظيفي
job = employee["job_title"]
print(f"المسمى الوظيفي: {job}")
الشرح:
إذا حاولت الوصول إلى مفتاح غير موجود بهذه الطريقة، سيحدث خطأ KeyError
ويتوقف البرنامج.
إضافة أو تعديل زوج
الوصف: نستخدم نفس صيغة الأقواس المربعة. إذا كان المفتاح موجودًا، سيتم تحديث قيمته. إذا لم يكن موجودًا، سيتم إنشاء زوج جديد من المفتاح-القيمة.
# تعديل قيمة موجودة
employee["years_experience"] = 6
# إضافة زوج جديد
employee["city"] = "الدار البيضاء"
print(f"البيانات المحدثة: {employee}")
حذف زوج
الوصف:
لحذف زوج مفتاح-قيمة من القاموس، نستخدم الكلمة المفتاحية del
متبوعة باسم القاموس والمفتاح.
del employee["is_remote"]
print(f"القاموس بعد حذف is_remote: {employee}")
الوصول الآمن باستخدام .get()
الوصف:
لتجنب خطأ KeyError
، الطريقة الأكثر أمانًا هي استخدام دالة get
. إذا لم تجد المفتاح، فإنها تعيد القيمة None
(أو قيمة افتراضية تحددها أنت) بدلاً من التسبب في خطأ.
# استخدام get للوصول الآمن لمفتاح
city = employee.get("city")
print(f"المدينة: {city}")
# الوصول لمفتاح غير موجود يعيد None
department = employee.get("department")
print(f"القسم: {department}")
# توفير قيمة افتراضية في حال عدم وجود المفتاح
salary = employee.get("salary", "غير محدد")
print(f"الراتب: {salary}")
التكرار على القواميس
الوصف:
الطريقة الأكثر شيوعًا وفعالية للتكرار على القاموس هي باستخدام دالة .items()
، التي تعطيك المفتاح والقيمة معًا في كل دورة.
print("\n--- تفاصيل الموظف ---")
for key, value in employee.items():
print(f"{key}: {value}")
الشرح:
في كل دورة من الحلقة، يتم وضع المفتاح في المتغير key
والقيمة المرتبطة به في المتغير value
، مما يسهل طباعتهما بشكل منظم.
4. تمرين تطبيقي: إدارة مخزون المنتجات
المطلوب:
كتابة برنامج بسيط لإدارة مخزون متجر. البرنامج يجب أن يستخدم قائمة لتخزين المنتجات، وكل منتج يجب أن يكون قاموسًا يحتوي على معلوماته (الاسم، السعر، والكمية).
الحل المقترح:
# الخطوة 1: إنشاء هيكل البيانات الرئيسي.
# نحتاج قائمة لتخزين كل المنتجات، وسنسميها inventory.
inventory = []
# الخطوة 2: تعريف المنتجات.
# كل منتج هو قاموس يحتوي على تفاصيله.
product1 = {"name": "حاسوب محمول", "price": 4500, "quantity": 10}
product2 = {"name": "فأرة", "price": 120, "quantity": 50}
product3 = {"name": "لوحة مفاتيح", "price": 250, "quantity": 30}
# الخطوة 3: إضافة المنتجات إلى قائمة المخزون
inventory.append(product1)
inventory.append(product2)
inventory.append(product3)
# الخطوة 4: عرض المخزون وحساب القيمة الإجمالية
print("--- مخزون المتجر الحالي ---")
total_value = 0
# نمر على كل "قاموس" في قائمة "inventory"
for item in inventory:
# نحسب قيمة مخزون هذا العنصر المحدد
item_stock_value = item["price"] * item["quantity"]
# نضيف هذه القيمة إلى المجموع الإجمالي
total_value += item_stock_value
# نطبع تفاصيل العنصر بشكل منظم
print(
f"العنصر: {item['name']}, "
f"السعر: {item['price']} درهم, "
f"الكمية: {item['quantity']}, "
f"قيمة المخزون: {item_stock_value} درهم"
)
# الخطوة 5: عرض القيمة الإجمالية النهائية لكل المخزون
print("-------------------------------")
print(f"القيمة الإجمالية لكل المنتجات في المخزون: {total_value} درهم")
5. خلاصة الفصل
- القوائم (Lists)
[]
: هي حاويتك اليومية المرنة. استخدمها عندما تحتاج إلى مجموعة مرتبة من العناصر يمكنك تعديلها باستمرار. - المجموعات الثابتة (Tuples)
()
: هي حاويتك الآمنة والثابتة. استخدمها عندما تريد التأكد من أن بياناتك لن تتغير أبدًا بعد إنشائها. - القواميس (Dictionaries)
{}
: هي بطاقتك التعريفية. استخدمها لربط البيانات ببعضها البعض باستخدام مفاتيح واضحة وذات معنى. - الجمع بين هذه الهياكل (مثل قائمة من القواميس) هو أسلوب قوي جدًا لتنظيم البيانات المعقدة في برامجك الواقعية.
تمارين تطبيقية
التمرين 1: تعديل قائمة المهام
المطلوب:
ابدأ بقائمة مهام tasks = ["دراسة بايثون", "كتابة التقرير"]
. قم بتنفيذ العمليات التالية بالترتيب، مع طباعة القائمة بعد كل خطوة:
- أضف مهمة “إرسال البريد الإلكتروني” إلى نهاية القائمة.
- أضف مهمة “الاتصال بالعميل” في بداية القائمة.
- احذف مهمة “كتابة التقرير”.
الحل:
# القائمة الأولية
tasks = ["دراسة بايثون", "كتابة التقرير"]
print(f"القائمة الأولية: {tasks}")
# 1. إضافة مهمة إلى النهاية
tasks.append("إرسال البريد الإلكتروني")
print(f"بعد إضافة مهمة جديدة: {tasks}")
# 2. إضافة مهمة في البداية (الفهرس 0)
tasks.insert(0, "الاتصال بالعميل")
print(f"بعد إدراج مهمة في البداية: {tasks}")
# 3. حذف مهمة "كتابة التقرير"
tasks.remove("كتابة التقرير")
print(f"القائمة النهائية: {tasks}")
شرح الحل:
- الخطوة 1 (
append
): دالة.append()
هي الطريقة المباشرة لإضافة عنصر إلى نهاية القائمة. لقد أضفنا “إرسال البريد الإلكتروني”، فأصبحت العنصر الأخير في القائمة. - الخطوة 2 (
insert
): دالة.insert()
تمنحنا تحكمًا أكبر، حيث تأخذ معاملين: الفهرس (الموقع) الذي نريد الإضافة فيه، والقيمة المراد إضافتها. باستخدامtasks.insert(0, ...)
، وضعنا المهمة الجديدة في الموقع الأول (فهرس 0)، مما أدى إلى إزاحة جميع العناصر الأخرى إلى اليمين. - الخطوة 3 (
remove
): دالة.remove()
تبحث عن القيمة التي نحددها (“كتابة التقرير”) وتقوم بحذف أول ظهور لها من القائمة.
التمرين 2: تقسيم أيام الأسبوع
المطلوب:
لديك قائمة تحتوي على أيام الأسبوع. استخدم الاقتطاع (Slicing) لإنشاء قائمتين جديدتين: واحدة تحتوي على أيام العمل (من الإثنين إلى الجمعة) وأخرى تحتوي على عطلة نهاية الأسبوع. ثم اطبع كل قائمة جديدة مع طولها باستخدام دالة len()
.
الحل:
days_of_week = ["الإثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"]
# اقتطاع أيام العمل (من الفهرس 0 إلى 4)
weekdays = days_of_week[:5]
print(f"أيام العمل ({len(weekdays)} أيام): {weekdays}")
# اقتطاع عطلة نهاية الأسبوع (من الفهرس 5 إلى النهاية)
weekend = days_of_week[5:]
print(f"عطلة نهاية الأسبوع ({len(weekend)} أيام): {weekend}")
شرح الحل:
weekdays = days_of_week[:5]
: هنا نستخدم الاقتطاع. النقطتان الرأسيتان (:
) هما مفتاح العملية.[:5]
تعني “ابدأ من بداية القائمة (الفهرس 0) واستمر حتى تصل إلى الفهرس 5، ولكن لا تشمل العنصر في الفهرس 5”. هذا يعطينا العناصر من فهرس 0 إلى 4.weekend = days_of_week[5:]
: بنفس الطريقة،[5:]
تعني “ابدأ من الفهرس 5 واستمر حتى تصل إلى نهاية القائمة”.len()
: هي دالة عامة تعيد عدد العناصر الموجودة في أي حاوية بيانات (قائمة، نص، قاموس، إلخ). استخدمناها هنا لطباعة عدد الأيام في كل قائمة جديدة.
التمرين 3: عداد الأرقام السالبة
المطلوب: لديك قائمة تحتوي على أرقام موجبة وسالبة. اكتب برنامجًا يقوم بالمرور على كل الأرقام في القائمة ويطبع فقط الأرقام السالبة، ثم في النهاية يطبع العدد الإجمالي للأرقام السالبة التي وجدها.
الحل:
numbers = [10, -5, 22, -3, 0, -15, 8]
negative_count = 0
print("الأرقام السالبة في القائمة:")
for num in numbers:
# تحقق إذا كان الرقم أصغر من صفر
if num < 0:
print(num)
negative_count += 1 # زيادة العداد
print(f"\nتم العثور على {negative_count} أرقام سالبة.")
شرح الحل:
negative_count = 0
: نبدأ بإنشاء متغير عداد بقيمة صفر. سنستخدمه لتتبع عدد الأرقام السالبة.for num in numbers:
: هذه حلقة تمر على كل عنصر في قائمةnumbers
، واحدًا تلو الآخر. في كل دورة، يتم تخزين العنصر الحالي في المتغير المؤقتnum
.if num < 0:
: داخل الحلقة، نستخدم جملة شرطية للتحقق مما إذا كان الرقم الحالي (num
) سالبًا.negative_count += 1
: إذا كان الشرط صحيحًا، نقوم بزيادة العدادnegative_count
بمقدار واحد. هذه طريقة مختصرة لكتابةnegative_count = negative_count + 1
.- بعد انتهاء الحلقة، نطبع القيمة النهائية للعداد.
التمرين 4: تفكيك الـ Tuple في حلقة
المطلوب:
لديك قائمة من المجموعات الثابتة (tuples)، حيث يمثل كل tuple
زوجًا من (اسم_المنتج, السعر)
. استخدم حلقة for
مع تفكيك الـ tuple لطباعة تفاصيل كل منتج في جملة منسقة.
الحل:
products = [
("لابتوب", 5200),
("شاشة", 1500),
("طابعة", 800)
]
print("--- قائمة أسعار المنتجات ---")
# تفكيك الـ tuple مباشرة إلى متغيرين: name و price
for name, price in products:
print(f"سعر المنتج '{name}' هو {price} درهم.")
شرح الحل:
- هيكل البيانات: لدينا قائمة
products
، كل عنصر فيها هوtuple
يحتوي على قيمتين. for name, price in products:
: هذا هو الجزء السحري. بدلاً من كتابةfor item in products:
ثم الوصول إلىitem[0]
وitem[1]
، تسمح لنا بايثون بـ تفكيك الـtuple
مباشرة في سطر الحلقة. في الدورة الأولى، يتم إسناد"لابتوب"
إلى المتغيرname
والرقم5200
إلى المتغيرprice
. هذا يجعل الكود داخل الحلقة أكثر وضوحًا وقراءة.
التمرين 5: إدارة إعدادات المستخدم
المطلوب: ابدأ بقاموس يمثل إعدادات مستخدم. قم بتنفيذ العمليات التالية بالترتيب، مع طباعة القاموس بعد كل خطوة:
- أضف إعدادًا جديدًا:
"language": "العربية"
. - عدّل قيمة الإعداد
"theme"
إلى"dark"
. - احذف الإعداد
"notifications_enabled"
.
الحل:
user_settings = {
"username": "user123",
"theme": "light",
"notifications_enabled": True
}
print(f"الإعدادات الأولية: {user_settings}")
# 1. إضافة إعداد جديد
user_settings["language"] = "العربية"
print(f"بعد إضافة اللغة: {user_settings}")
# 2. تعديل إعداد موجود
user_settings["theme"] = "dark"
print(f"بعد تغيير الثيم: {user_settings}")
# 3. حذف إعداد
del user_settings["notifications_enabled"]
print(f"الإعدادات النهائية: {user_settings}")
شرح الحل:
- الإضافة:
user_settings["language"] = "العربية"
. عندما نستخدم صيغة الأقواس المربعة[]
مع مفتاح غير موجود ("language"
في هذه الحالة)، تقوم بايثون بإنشاء هذا المفتاح الجديد وإضافة القيمة المرتبطة به. - التعديل:
user_settings["theme"] = "dark"
. عندما نستخدم نفس الصيغة مع مفتاح موجود بالفعل ("theme"
في هذه الحالة)، تقوم بايثون بتحديث قيمته القديمة بالقيمة الجديدة. - الحذف: الكلمة المفتاحية
del
تُستخدم لحذف زوج مفتاح-قيمة بالكامل من القاموس.
التمرين 6: مترجم بسيط
المطلوب:
أنشئ قاموسًا يمثل مترجمًا بسيطًا من الإنجليزية إلى العربية. اطلب من المستخدم إدخال كلمة باللغة الإنجليزية. استخدم دالة .get()
للبحث عن الكلمة في القاموس. إذا كانت موجودة، اطبع ترجمتها. إذا لم تكن موجودة، اطبع “الكلمة غير موجودة في القاموس.”
الحل:
translator = {
"book": "كتاب",
"tree": "شجرة",
"car": "سيارة"
}
word_to_translate = input("أدخل كلمة إنجليزية لترجمتها: ").lower()
# استخدام .get() للبحث الآمن عن الكلمة
translation = translator.get(word_to_translate, "الكلمة غير موجودة في القاموس.")
print(f"الترجمة: {translation}")
شرح الحل:
- المشكلة: إذا استخدمنا
translator[word_to_translate]
وحاول المستخدم البحث عن كلمة غير موجودة، سيتوقف البرنامج مع خطأKeyError
. - الحل: دالة
.get()
هي الطريقة الآمنة للبحث. تأخذ معاملين:- المفتاح الذي نبحث عنه (
word_to_translate
). - قيمة افتراضية اختيارية يتم إرجاعها فقط إذا لم يتم العثور على المفتاح.
- المفتاح الذي نبحث عنه (
- في هذا الكود، إذا كانت الكلمة موجودة، سيعيد
.get()
الترجمة. إذا لم تكن موجودة، سيعيد النص “الكلمة غير موجودة في القاموس.”، كل ذلك بدون أي أخطاء.
التمرين 7: طباعة تقرير الدرجات
المطلوب:
لديك قاموس يحتوي على أسماء الطلاب كـ “مفاتيح” ودرجاتهم كـ “قيم”. استخدم حلقة for
مع دالة .items()
لطباعة تقرير درجات منسق لكل طالب.
الحل:
student_grades = {
"أحمد": 85,
"فاطمة": 92,
"يوسف": 78,
"مريم": 95
}
print("--- تقرير درجات الطلاب ---")
for student, grade in student_grades.items():
print(f"الطالب/ة {student} حصل/ت على درجة {grade}%.")
شرح الحل:
- إذا استخدمنا
for student in student_grades:
، سنحصل على المفاتيح فقط (“أحمد”، “فاطمة”، …). - دالة
.items()
هي الأداة المثالية للتكرار على القواميس. في كل دورة، تعيد زوجًا من(المفتاح, القيمة)
. - باستخدام
for student, grade in ...
، نستخدم ميزة تفكيك الـ tuple (مثل التمرين 4) لإسناد المفتاح إلى المتغيرstudent
والقيمة إلى المتغيرgrade
تلقائيًا في كل دورة، مما يجعل الكود نظيفًا وسهل القراءة.
التمرين 8: البحث عن موظف
المطلوب:
لديك قائمة من القواميس، حيث يمثل كل قاموس موظفًا له id
و name
. اكتب برنامجًا يطلب من المستخدم إدخال id
موظف، ثم يبحث البرنامج في القائمة عن هذا الموظف. إذا وجده، يطبع اسمه. إذا لم يجده بعد البحث في كل القائمة، يطبع “الموظف غير موجود.”
الحل:
employees = [
{"id": 101, "name": "سمير"},
{"id": 102, "name": "هناء"},
{"id": 103, "name": "كريم"}
]
search_id = int(input("أدخل الرقم التعريفي للموظف للبحث عنه: "))
found_employee = False # متغير لتتبع إذا تم العثور على الموظف
for employee in employees:
if employee["id"] == search_id:
print(f"تم العثور على الموظف: {employee['name']}")
found_employee = True
break # اخرج من الحلقة لأننا وجدنا الموظف
if not found_employee:
print("الموظف غير موجود.")
شرح الحل:
- هيكل البيانات: لدينا قائمة، كل عنصر فيها هو قاموس. هذا هيكل شائع جدًا.
found_employee = False
: هذا متغير “عَلَم” (flag). نرفعه (نغير قيمته إلىTrue
) فقط إذا تحقق شرط معين.- الحلقة والشرط: نمر على كل قاموس (
employee
) في القائمة. داخل الحلقة، نصل إلى قيمة المفتاح"id"
باستخدامemployee["id"]
ونقارنها بالرقم الذي أدخله المستخدم. break
: إذا وجدنا تطابقًا، نطبع الاسم، ونغير قيمة العلم إلىTrue
، ثم نستخدمbreak
لإيقاف الحلقة فورًا. لا داعي لإكمال البحث لأننا وجدنا ما نريده.- التحقق النهائي: بعد انتهاء الحلقة، نتحقق من قيمة العلم. إذا بقيت
False
، فهذا يعني أن الحلقة انتهت بشكل طبيعي دون العثور على أي تطابق.
التمرين 9: إجمالي المبيعات حسب الفئة
المطلوب:
لديك قائمة من القواميس تمثل مبيعات. كل قاموس يحتوي على category
(الفئة) و amount
(المبلغ). اكتب برنامجًا يحسب إجمالي المبيعات لكل فئة ويخزن النتائج في قاموس جديد.
الحل:
sales_data = [
{"category": "إلكترونيات", "amount": 1200},
{"category": "ملابس", "amount": 300},
{"category": "إلكترونيات", "amount": 800},
{"category": "أدوات منزلية", "amount": 450},
{"category": "ملابس", "amount": 150}
]
sales_by_category = {}
for sale in sales_data:
category = sale["category"]
amount = sale["amount"]
if category in sales_by_category:
sales_by_category[category] += amount
else:
sales_by_category[category] = amount
print("--- إجمالي المبيعات حسب الفئة ---")
for category, total in sales_by_category.items():
print(f"{category}: {total} درهم")
شرح الحل:
sales_by_category = {}
: نبدأ بقاموس فارغ. هذا القاموس سيحتوي على النتائج النهائية، حيث ستكون المفاتيح هي أسماء الفئات والقيم هي إجمالي المبيعات.- الحلقة: نمر على كل عملية بيع (
sale
) في قائمتنا. if category in sales_by_category:
: هذا هو المنطق الأساسي. في كل دورة، نسأل: “هل هذه الفئة (category
) موجودة بالفعل كمفتاح في قاموس النتائج؟”.- إذا كانت الإجابة نعم: فهذا يعني أننا رأينا هذه الفئة من قبل. كل ما علينا فعله هو إضافة المبلغ الحالي (
amount
) إلى القيمة الموجودة بالفعل:sales_by_category[category] += amount
. - إذا كانت الإجابة لا: فهذه هي المرة الأولى التي نرى فيها هذه الفئة. نقوم بإنشاء مفتاح جديد لها في قاموس النتائج ونعطيه القيمة الأولية للمبلغ الحالي:
sales_by_category[category] = amount
.
- إذا كانت الإجابة نعم: فهذا يعني أننا رأينا هذه الفئة من قبل. كل ما علينا فعله هو إضافة المبلغ الحالي (
- في النهاية، نطبع قاموس النتائج المجمع.
التمرين 10: دليل هاتف بسيط
المطلوب:
أنشئ دليل هاتف بسيطًا باستخدام قاموس متداخل. القاموس الرئيسي يجب أن تكون مفاتيحه هي أسماء الأشخاص، وقيمه هي قواميس أخرى تحتوي على مفتاحين: phone
و email
.
- أنشئ القاموس مع جهتي اتصال على الأقل.
- اطلب من المستخدم إدخال اسم للبحث عنه.
- إذا كان الاسم موجودًا، اطبع رقم الهاتف والبريد الإلكتروني للشخص.
- إذا لم يكن موجودًا، اطبع رسالة تفيد بأن جهة الاتصال غير موجودة.
الحل:
# 1. إنشاء دليل الهاتف
phone_book = {
"نورة": {"phone": "0611223344", "email": "[email protected]"},
"خالد": {"phone": "0655667788", "email": "[email protected]"}
}
# 2. طلب اسم من المستخدم
search_name = input("أدخل اسم جهة الاتصال للبحث عنها: ")
# 3. البحث باستخدام .get()
contact_info = phone_book.get(search_name)
# 4. التحقق من النتيجة وطباعة المعلومات
if contact_info:
print(f"\n--- معلومات {search_name} ---")
print(f"رقم الهاتف: {contact_info['phone']}")
print(f"البريد الإلكتروني: {contact_info['email']}")
else:
print(f"عذرًا، جهة الاتصال '{search_name}' غير موجودة.")
شرح الحل:
- هيكل البيانات: هذا “قاموس من القواميس”. المفتاح الرئيسي (
"نورة"
) يشير إلى قيمة هي نفسها قاموس آخر ({"phone": ..., "email": ...}
). contact_info = phone_book.get(search_name)
: نستخدم.get()
للبحث عن الاسم الذي أدخله المستخدم في مفاتيح القاموس الرئيسي.if contact_info:
: نستخدم هنا مفهوم Truthy/Falsy.- إذا تم العثور على الاسم، سيعيد
.get()
القاموس الداخلي (الذي يعتبرTrue
)، وسيتم تخزينه فيcontact_info
. - إذا لم يتم العثور على الاسم، سيعيد
.get()
القيمةNone
(التي تعتبرFalse
).
- إذا تم العثور على الاسم، سيعيد
- الوصول للبيانات المتداخلة: عندما يكون
contact_info
يحتوي على القاموس الداخلي، يمكننا الوصول إلى قيمه باستخدام مفاتيحه الخاصة، مثلcontact_info['phone']
.
ماذا بعد؟
بعد أن أتقنت تنظيم البيانات في ذاكرة البرنامج، سننتقل في الفصل الثامن لنتعلم كيفية التعامل مع الملفات، مما سيسمح لنا بحفظ هذه الهياكل البيانية بشكل دائم على القرص الصلب وقراءتها مرة أخرى لاحقًا، حتى بعد إغلاق البرنامج.