بعد أن تتعلم القوائم والقواميس والحلقات والشروط، تحتاج إلى مشروع صغير يجمعها في برنامج واحد مفهوم. في هذا المثال سننشئ برنامج اختبار أسئلة وأجوبة: يعرض سؤالًا مع عدة خيارات، يقرأ إجابة المستخدم، يتحقق من صحتها، ثم يحسب النتيجة والنسبة المئوية في النهاية.
الفكرة مناسبة جدًا للتجربة داخل محرر بايثون أو Terminal، ويمكنك تطويرها لاحقًا بإضافة أسئلة جديدة أو مستويات مختلفة أو إعادة تشغيل الاختبار.
{alertInfo}
الفكرة ببساطة: سنخزن كل سؤال وخياراته والإجابة الصحيحة داخل قاموس، ثم نضع كل القواميس داخل قائمة. بعد ذلك نمر على الأسئلة بحلقة for، ونقارن إجابة المستخدم بالإجابة الصحيحة لزيادة النتيجة عند النجاح.
{getToc} $title={محتوى المقال}
ماذا سنتعلم من هذا المثال؟
- تنظيم بيانات متعددة داخل
listمن القواميس. - عرض الأسئلة والخيارات باستخدام حلقة
for. - استقبال إجابة المستخدم عبر
input(). - توحيد شكل الإدخال باستخدام
strip()وlower(). - التحقق من صحة الإجابة باستخدام
if. - زيادة عداد النتيجة عند الإجابة الصحيحة.
- حساب نسبة النتيجة وإظهار رسالة مناسبة للمستخدم.
كيف نفكر في شكل بيانات الاختبار؟
لكل سؤال نحتاج إلى نص السؤال، والخيارات، وحرف الإجابة الصحيحة، وشرح قصير يظهر عند الإجابة الخاطئة. القاموس مناسب لتجميع هذه المعلومات في مكان واحد، والقائمة مناسبة لأنها تحفظ عدة أسئلة بالترتيب.
question = {
"question": "أي كلمة نستخدمها لتعريف دالة في بايثون؟",
"options": {
"a": "def",
"b": "loop",
"c": "return",
},
"answer": "a",
"explanation": "نستخدم def قبل اسم الدالة.",
}
هنا المفتاح question يحمل نص السؤال، وoptions يحمل قاموسًا صغيرًا للخيارات، بينما answer يحدد حرف الإجابة الصحيح.
النسخة الأولى: سؤال واحد فقط
ابدأ دائمًا بنسخة صغيرة. هذا البرنامج يعرض سؤالًا واحدًا ويخبر المستخدم هل كانت إجابته صحيحة:
correct_answer = "a"
print("أي كلمة نستخدمها لتعريف دالة في بايثون؟")
print("A) def")
print("B) loop")
print("C) return")
user_answer = input("اكتب حرف الإجابة: ").strip().lower()
if user_answer == correct_answer:
print("إجابة صحيحة ✓")
else:
print("إجابة غير صحيحة. الإجابة هي A.")
استخدمنا strip() لإزالة المسافات الزائدة، وlower() لتحويل الحرف إلى صغير. لذلك لو كتب المستخدم A أو a أو أضاف مسافة قبلها أو بعدها، ستبقى المقارنة صحيحة.
لماذا نضع الأسئلة في قائمة من القواميس؟
لو كتبنا كل سؤال في مجموعة أوامر print() منفصلة، سيصبح البرنامج طويلًا وصعب التعديل عند إضافة أسئلة جديدة. أما القائمة من القواميس فتسمح لك بإضافة سؤال كامل في بضعة أسطر فقط.
questions = [
{
"question": "أي كلمة نستخدمها لتعريف دالة في بايثون؟",
"options": {
"a": "def",
"b": "loop",
"c": "return",
},
"answer": "a",
"explanation": "نستخدم def قبل اسم الدالة.",
},
{
"question": "ما الدالة التي تعيد عدد عناصر القائمة؟",
"options": {
"a": "sum()",
"b": "len()",
"c": "print()",
},
"answer": "b",
"explanation": "تستخدم len() لمعرفة عدد العناصر.",
},
]
عرض الخيارات باستخدام حلقة for
بداخل كل سؤال يوجد قاموس للخيارات. نستطيع المرور على الحرف والنص معًا باستخدام items():
for letter, option in item["options"].items():
print(f"{letter.upper()}) {option}")
إذا كان letter يساوي "a" وoption يساوي "def"، سيظهر للمستخدم A) def.
راجع بايثون بالمثال 10: البحث عن عنصر داخل قائمة والفرق بين القائمة والقاموس والمجموعة والصف إذا احتجت إلى مراجعة القوائم والقواميس قبل متابعة التطبيق.
الكود الكامل لبرنامج الاختبار
انسخ الكود التالي إلى ملف باسم quiz_app.py، ثم شغّله من Terminal أو داخل محرر بايثون:
def normalize_answer(answer):
return answer.strip().lower()
def get_feedback(percentage):
if percentage == 100:
return "نتيجة ممتازة! أجبت عن كل الأسئلة بشكل صحيح."
if percentage >= 70:
return "نتيجة جيدة جدًا. راجع الأسئلة التي أخطأت فيها."
if percentage >= 40:
return "بداية جيدة. أعد قراءة الشرح ثم جرّب مرة أخرى."
return "لا بأس. تعلّم من الإجابات الصحيحة وحاول من جديد."
def run_quiz(questions):
score = 0
print("=" * 45)
print("اختبار بايثون للمبتدئين")
print("=" * 45)
for number, item in enumerate(questions, start=1):
print(f"\nالسؤال {number}: {item['question']}")
for letter, option in item["options"].items():
print(f"{letter.upper()}) {option}")
user_answer = normalize_answer(
input("اكتب حرف الإجابة الصحيحة: ")
)
while user_answer not in item["options"]:
print("اختر حرفًا موجودًا من الخيارات المعروضة.")
user_answer = normalize_answer(
input("اكتب حرف الإجابة الصحيحة: ")
)
if user_answer == item["answer"]:
score += 1
print("إجابة صحيحة ✓")
else:
correct_answer = item["answer"].upper()
print(f"إجابة غير صحيحة. الإجابة الصحيحة: {correct_answer}")
print(f"الشرح: {item['explanation']}")
total_questions = len(questions)
percentage = (score / total_questions) * 100
print("\n" + "=" * 45)
print(f"نتيجتك: {score} من {total_questions}")
print(f"النسبة: {percentage:.0f}%")
print(get_feedback(percentage))
questions = [
{
"question": "أي كلمة نستخدمها لتعريف دالة في بايثون؟",
"options": {
"a": "def",
"b": "loop",
"c": "return",
},
"answer": "a",
"explanation": "نستخدم def قبل اسم الدالة.",
},
{
"question": "ما الدالة التي تعيد عدد عناصر القائمة؟",
"options": {
"a": "sum()",
"b": "len()",
"c": "print()",
},
"answer": "b",
"explanation": "تستخدم len() لمعرفة عدد العناصر.",
},
{
"question": "أي تعليمة نستخدمها لاتخاذ قرار بناءً على شرط؟",
"options": {
"a": "if",
"b": "import",
"c": "break",
},
"answer": "a",
"explanation": "تستخدم if لفحص شرط وتنفيذ كود عند تحققه.",
},
]
run_quiz(questions)
مثال على نتيجة التشغيل
=============================================
اختبار بايثون للمبتدئين
=============================================
السؤال 1: أي كلمة نستخدمها لتعريف دالة في بايثون؟
A) def
B) loop
C) return
اكتب حرف الإجابة الصحيحة: a
إجابة صحيحة ✓
...
=============================================
نتيجتك: 2 من 3
النسبة: 67%
بداية جيدة. أعد قراءة الشرح ثم جرّب مرة أخرى.
شرح البرنامج خطوة بخطوة
1. توحيد إجابة المستخدم
def normalize_answer(answer):
return answer.strip().lower()
لو كتب المستخدم مسافة قبل الحرف أو بعده، تحذفها strip(). ولو كتب الحرف كبيرًا مثل A، تحوله lower() إلى a. هذا يجعل التعامل مع الإدخال أسهل بدل رفض إجابة صحيحة بسبب شكل كتابتها.
2. المرور على الأسئلة
for number, item in enumerate(questions, start=1):
الدالة enumerate() تعطيك رقم السؤال والعنصر نفسه أثناء المرور داخل القائمة. استخدمنا start=1 حتى يبدأ ترقيم الأسئلة من 1 بدل 0.
3. منع إجابة غير موجودة
while user_answer not in item["options"]:
print("اختر حرفًا موجودًا من الخيارات المعروضة.")
هذا الشرط مهم. بدونه قد يكتب المستخدم z أو رقمًا أو كلمة كاملة، وسيحسب البرنامج الإجابة خاطئة دون أن يوضح أن الخيار غير موجود. باستخدام while نطلب إدخالًا جديدًا حتى يختار المستخدم أحد الحروف المتاحة.
4. زيادة النتيجة
if user_answer == item["answer"]:
score += 1
المتغير score يبدأ من صفر. في كل مرة تكون الإجابة مطابقة للإجابة الصحيحة، نضيف إليه واحدًا.
5. حساب النسبة المئوية
percentage = (score / total_questions) * 100
نقسم عدد الإجابات الصحيحة على إجمالي عدد الأسئلة، ثم نضرب الناتج في 100. استخدمنا :.0f داخل النص المنسق لطباعة النسبة من دون أرقام عشرية.
كيف تضيف سؤالًا جديدًا؟
أضف قاموسًا جديدًا داخل القائمة questions بالهيكل نفسه:
{
"question": "ما الكلمة التي نستخدمها لاستيراد مكتبة؟",
"options": {
"a": "import",
"b": "input",
"c": "class",
},
"answer": "a",
"explanation": "نستخدم import لاستيراد المكتبات والوحدات.",
},
لا تغير مفاتيح القاموس مثل question أو options أو answer في سؤال واحد فقط، لأن دالة الاختبار تعتمد على هذه الأسماء في كل الأسئلة.
تحسينات يمكنك إضافتها لاحقًا
- خلط ترتيب الأسئلة في كل تشغيل.
- إضافة مؤقت بسيط لكل سؤال.
- إعادة الاختبار من البداية عند طلب المستخدم.
- تقسيم الأسئلة إلى مستويات: مبتدئ ومتوسط.
- قراءة الأسئلة من ملف JSON بدل كتابتها داخل الكود.
- إظهار الإجابات الصحيحة كلها في النهاية بدل عرضها فورًا.
أخطاء شائعة في هذا المشروع
1. كتابة الإجابة الصحيحة كنص الخيار بدل حرف الخيار
في هذا المثال نخزن "a" أو "b" في المفتاح answer، لأن المستخدم يكتب حرفًا. لا تكتب "def" في الإجابة الصحيحة ثم تقارنها مباشرة بإدخال "a"؛ النوعان مختلفان.
2. نسيان إعادة score إلى صفر
ضع score = 0 في بداية دالة run_quiz. بهذه الطريقة يبدأ كل تشغيل بنتيجة جديدة.
3. القسمة على قائمة فارغة
إذا حذفت كل الأسئلة ثم شغلت البرنامج، ستكون total_questions مساوية للصفر، وستظهر مشكلة عند حساب النسبة. عند تطوير المشروع تحقق دائمًا من أن القائمة ليست فارغة.
4. قبول خيار خارج القائمة
استخدم حلقة while للتحقق من أن الإجابة موجودة في مفاتيح options. هذا يجعل البرنامج أوضح للمستخدم.
5. تكرار كود السؤال يدويًا
تخزين الأسئلة داخل قائمة من القواميس يمنع نسخ كود الطباعة والتحقق لكل سؤال، ويجعل إضافة الأسئلة أسهل.
روابط داخلية مفيدة من بايثون العرب
- أساسيات بايثون 11: شرح if وelse للمبتدئين
- أساسيات بايثون 14: شرح return في الدوال
- بايثون بالمثال 10: البحث عن عنصر داخل قائمة
- الفرق بين القائمة والقاموس والمجموعة والصف في بايثون
- محرر بايثون أونلاين لتجربة الكود
- أفضل مشاريع بايثون للمبتدئين
الخلاصة
- القائمة من القواميس طريقة مرتبة لتخزين أسئلة متعددة وخياراتها.
- تساعد حلقة
forعلى عرض كل سؤال وخياراته دون تكرار الكود. - استخدم
strip()وlower()لتوحيد شكل إجابة المستخدم. - استخدم
whileللتأكد من أن المستخدم اختار حرفًا موجودًا. - تزداد النتيجة بواسطة
score += 1عند الإجابة الصحيحة. - تحسب النسبة بقسمة الإجابات الصحيحة على إجمالي الأسئلة ثم الضرب في 100.
{alertSuccess} تطبيق مهم: لا تكتفِ بتشغيل البرنامج كما هو. أضف 5 أسئلة من الدروس التي تعلمتها، ثم جرّب الإجابة عليها بنفسك. تعديل المشروع هو أسرع طريقة لفهم القوائم والقواميس والحلقات.
مصادر رسمية للتوسع
أسئلة شائعة
هل يمكن أن أضيف أكثر من ثلاثة خيارات للسؤال؟
نعم. أضف خيارات جديدة داخل القاموس options مثل "d"، ثم تأكد من كتابة حرف الإجابة الصحيح في answer.
لماذا نستخدم قائمة من القواميس بدل قائمة من النصوص؟
لأن كل سؤال يحتاج أكثر من معلومة: نص السؤال، الخيارات، الإجابة الصحيحة، والشرح. القاموس يجمع هذه المعلومات، والقائمة تجمع كل الأسئلة.
هل يمكن أن يقبل البرنامج الإجابة العربية بدل الحروف؟
نعم، لكن ذلك يحتاج منطقًا مختلفًا للمقارنة مع نصوص الخيارات. البدء بالحروف a وb وc يجعل المثال أوضح للمبتدئ.
كيف أجعل الأسئلة تظهر بترتيب مختلف كل مرة؟
يمكنك خلط نسخة من القائمة قبل تشغيل الاختبار. نفّذ هذه الإضافة بعد فهم النسخة الحالية، ولا تغيّر القائمة الأصلية بلا حاجة إذا كنت تريد الاحتفاظ بترتيبها.
هل يمكن أن أحفظ الأسئلة في ملف خارجي؟
نعم. الخطوة التالية المناسبة هي تخزينها في ملف JSON ثم قراءتها عند بدء البرنامج. بهذه الطريقة تضيف أسئلة دون تعديل منطق الاختبار نفسه.



