الأسبوع 2: التحكم في تدفق التنفيذ
🎯 أهداف التعلّم
بنهاية هذا الأسبوع ستكون قادرًا على:
- تفريع سلوك البرنامج باستخدام
if/elif/else. - دمج الشروط باستخدام
and،or، وnot. - تكرار العمل باستخدام حلقتي
whileوfor، واختيار المناسبة منهما. - استخدام
range()للتكرار عددًا ثابتًا من المرات، واستخدامbreak/continueللتحكم بالحلقة مبكرًا. - تضمين الحلقات والشروط داخل بعضها لحل مسائل بها أكثر من عنصر متغيّر.
الدرس
التفريع: if / elif / else
جملة if هي تعريف مجزّأ (piecewise). قارن (القيم بين علامتي التنصيص هنا بالإنجليزية فقط لأن محرّك عرض الرياضيات KaTeX المستخدم في الموقع لا يدعم رسم الأحرف العربية داخل الصيغ الرياضية؛ negative تعني "سالب"، zero تعني "صفر"، positive تعني "موجب"):
x = -3
if x < 0:
print("negative")
elif x == 0:
print("zero")
else:
print("positive")
المسافة البادئة هنا ليست مجرد أسلوب — إنها الصياغة نفسها. كل ما هو مُزاح تحت if ينتمي لذلك الفرع؛ لا تملك بايثون { } لتحديد الكتل. تحتاج الكتلة إلى جملة واحدة على الأقل — فإن أردت فرعًا لا يفعل شيئًا عمدًا (مثلًا أثناء رسم هيكل البرنامج قبل ملئه)، استخدم pass، وهي جملة مهمتها الوحيدة ألا تفعل شيئًا:
if x < 0:
pass # TODO: handle negative numbers later
else:
print("non-negative")
دمج الشروط: and، or، not
تمامًا مثل ، ، في المنطق، تمتلك بايثون and، or، not لدمج التعبيرات المنطقية:
age = 20
has_ticket = True
if age >= 18 and has_ticket:
print("Welcome in")
if age < 13 or age > 65:
print("Discount applies")
if not has_ticket:
print("Buy a ticket first")
تتبع نفس جداول الصدق التي تتوقعها: and تكون صحيحة فقط عندما يكون كلا الطرفين صحيحين؛ or تكون صحيحة عندما يكون طرف واحد على الأقل صحيحًا؛ not تعكس القيمة المنطقية. كما تقوم بايثون بـ"التقييم المختصر" (short-circuit): في a and b، إذا كانت a بالفعل False، فإن بايثون لا تُقيّم b إطلاقًا، لأن التعبير كله يجب أن يكون False بغض النظر. يهم هذا عندما يكون تقييم b مكلفًا أو غير آمن — فمثلًا x != 0 and 10 / x > 1 لا تخاطر أبدًا بالقسمة على صفر، لأنه إذا كانت x != 0 تساوي False، تُتخطى القسمة تمامًا.
while: التكرار حتى يفشل الشرط
حلقة while هي أقرب شيء لعلاقة تكرارية رياضية مع شرط توقف:
n = 5
while n > 0:
print(n)
n = n - 1
print("liftoff!")
يطبع هذا 5 4 3 2 1 liftoff!. تعيد الحلقة فحص n > 0 قبل كل تكرار — إن نسيت تحديث n داخل الحلقة، فلن تصبح False أبدًا، وستحصل على حلقة لا نهائية.
while هي الأداة الصحيحة عندما لا تعرف مسبقًا عدد التكرارات التي ستحتاجها — يعتمد شرط التوقف على شيء يحدث أثناء الحلقة، مثل إدخال المستخدم أو بحث قد ينتهي مبكرًا:
guess = None
target = 42
while guess != target:
guess = int(input("Guess the number: "))
print("Correct!")
for: التكرار عبر متتالية معروفة
تسير حلقة for مباشرة عبر متتالية من القيم — فكّر فيها كـ حيث هي أيًا ما تكرر عليه، إلا أنك تنفّذ كودًا لكل بدلًا من جمع أرقام:
for letter in "cat":
print(letter) # c, a, t — واحد في كل سطر
تُنتج range(n) المتتالية — بالضبط مجموعة الفهارس التي تستخدمها لـ :
total = 0
for i in range(5):
total = total + i
print(total) # 0+1+2+3+4 = 10
تعمّم range(start, stop) وrange(start, stop, step) هذه الفكرة، مما يعكس متتالية حسابية :
for i in range(2, 10, 2):
print(i) # 2, 4, 6, 8 — تبدأ من 2، تتوقف قبل 10، بخطوة 2
الخطوة السالبة تُنقص: range(5, 0, -1) تُنتج 5, 4, 3, 2, 1، نفس المتتالية التي بناها مثال while الخاص بالإقلاع في الأسبوع 1 يدويًا.
break وcontinue
تُنهي break الحلقة فورًا؛ تنتقل continue إلى التكرار التالي دون إنهاء التكرار الحالي:
for i in range(10):
if i == 5:
break # توقف تمامًا عندما تصل i إلى 5
if i % 2 == 0:
continue # تخطَّ طباعة الأعداد الزوجية
print(i) # يطبع 1, 3
التضمين: حلقات وشروط داخل بعضها
يمكن لجسم حلقة — أو فرع if — أن يحتوي على حلقة أو if أخرى، تمامًا كما يمكن لحالات دالة معرّفة بالتجزئة أن تتضمن شروطًا إضافية. كل مستوى تضمين يضيف مستوى إضافيًا من المسافة البادئة:
for row in range(1, 4):
for col in range(1, 4):
print(row * col, end=" ") # end=" " تطبع مسافة بدلًا من سطر جديد
print() # انتقل لسطر جديد بعد كل صف
يطبع هذا جدول ضرب صغير بحجم 3×3:
1 2 3
2 4 6
3 6 9
تُنفَّذ الحلقة الداخلية بالكامل في كل تكرار للحلقة الخارجية — لثلاثة تكرارات خارجية وثلاثة داخلية لكل منها، هذا جملة طباعة إجمالًا، نفس مبدأ العدّ وراء المجموع المزدوج .
⚠️ أخطاء شائعة
- أخطاء الحدود مع
range. تتوقفrange(1, 10)قبل 10، فتُعطي1..9. إن أردت تضمين 10، تحتاجrange(1, 11). - نسيان تحديث متغيّر الحلقة في
while.while n > 0: print(n)دونn -= 1بداخلها لا تتوقف أبدًا. - استخدام
=بدلًا من==في شرط. تلتقط بايثون هذا الخطأ فعليًا نيابة عنك (if x = 5:تُعتبرSyntaxError)، بخلاف بعض اللغات الأخرى — لكن يظل من المفيد معرفة لماذا سيكون هذا خطأً لو كان مسموحًا. - افتراض أن سلاسل
elifتفحص كل الفروع. بمجرد تطابق شرطelif/ifواحد، يُتخطى الباقي تمامًا — الترتيب مهم، خصوصًا للشروط المتداخلة مثل حالة "القابلية للقسمة على 3 و5 معًا" في FizzBuzz.
🧩 تحديات
اكتب "FizzBuzz" للأعداد من 1 إلى 10: اطبع "Fizz" إذا كان العدد قابلًا للقسمة على 3، "Buzz" إذا كان قابلًا للقسمة على 5، "FizzBuzz" إذا كان قابلًا للقسمة على كليهما، وإلا اطبع العدد نفسه.
اكتب حلقة تستمر في طلب "Type 'quit' to stop: " حتى يكتب الطالب quit بالضبط. هل تناسب for أم while هذه المهمة بشكل أفضل، ولماذا؟
اجمع الأعداد الصحيحة من 1 إلى 100 باستخدام حلقة، وتحقق من إجابة برنامجك مقابل الصيغة المغلقة .
اكتب برنامجًا يقرأ عددًا n ويطبع ما إذا كان أوليًا، بفحص ما إذا كان أي عدد صحيح من 2 حتى (لكن دون تضمين) n يقسمه بالتمام.
باستخدام حلقات متداخلة، اطبع مربعًا من علامات النجمة، بحجم n صفًا وn عمودًا، لعدد n من اختيارك (مثل كتلة 4×4 من رمز *).
اكتب شرطًا باستخدام and يفحص ما إذا كان متغيّر age بين 18 و65 (شاملًا 18، غير شامل 65) وأن قيمة has_ticket المنطقية تساوي True.
🤔 أسئلة سقراطية
- ماذا يحدث إن كتبت
while True:دونbreakبداخلها؟ جرّب ذلك بحذر في الملعب البرمجي (قد تحتاج لإيقاف التنفيذ يدويًا) — لماذا يختلف هذا عن حلقةforعلىrangeثابت؟ - في FizzBuzz، لماذا يجب فحص حالة القابلية للقسمة على كليهما (
FizzBuzz) قبل فحصيFizz/Buzzالمنفصلين، أو معالجتها بـand؟ ما الذي سيحدث خطأً مع ترتيبelifساذج؟ - تفعل
for i in range(5):وi = 0; while i < 5: ...; i += 1نفس الشيء. في أي ظروف ستضطر لاستخدامwhileلأنforلا يستطيع التعبير عنها فعليًا؟ - يعني التقييم المختصر أن
a and bتتخطى تقييمbإذا كانتaبالفعلFalse. هل يمكنك التفكير في موقف (بخلاف مثال القسمة على صفر أعلاه) يهم فيه هذا لأكثر من مجرد الأداء — حيث يكون تقييمbعندما لا ينبغي تقييمها خطأً فعليًا، وليس مجرد إهدار؟ - يُضمّن مثال جدول الضرب حلقة
forداخلfor. كيف سيبدو تضمينwhileداخلfor، وهل يمكنك التفكير في مهمة حقيقية (وليس مجرد مثال مُختلق) يكون فيها هذا الدمج هو الخيار الطبيعي؟