حلقات for ودالة range — التكرار لعدد محدد من المرات
عندما تعرف عدد مرات التكرار، فإن حلقة for هي الخيار المثالي. الأشكال الثلاثة لدالة range، ولماذا يُستثنى الحد الأخير، وكيف تختار بين for و while.
- 1المشكلة
- 2الفهم
- 3أمثلة محلولة
- 4التوقع
- 5التطبيق
- 6التحدي
المشكلة التي نقوم بحلها
في الدرس السابق، تطلّب حساب مجموع الأرقام من 1 إلى 5 أربعة أسطر، سطران منها كانا مخصصين فقط لتتبع العدّ — قيمة ابتدائية ومقدار زيادة. وإذا نسيت مقدار الزيادة، فستقع في حلقة لانهائية.
لكن لاحظ أمراً مهماً حول هذا النوع من المهام: كنا نعرف مسبقاً عدد المرات التي سيتكرر فيها التنفيذ. خمس مرات. وعندما تكون هذه هي الحالة، لا يوجد سبب لتحمل عناء إدارة العداد بنفسك — يمكنك ترك هذه المهمة لبايثون بالكامل.
هذا هو بالضبط ما تفعله حلقة for. ولأن العدّ لم يعد بيدك، فإن حلقة for لا يمكن أن تصبح لانهائية أبداً — وهذه هي أكبر ميزة لها على الإطلاق.
في نهاية هذا الدرس ستكون قادراً على
- تشغيل الكود لعدد معروف من المرات باستخدام حلقة
for - استخدام الأشكال الثلاثة لدالة
range() - شرح لماذا ينتج عن
range(1, 5)أربعة أرقام وليس خمسة - التكرار على أحرف نص معين حرفاً بحرف
- تحديد ما إذا كانت المهمة تتطلب استخدام
forأمwhile
المتطلبات السابقة: حلقات while — التكرار طالما تحقق الشرط.
أبسط صورة لحلقة for
for number in range(5):
print(number)0
1
2
3
4ثلاثة أسطر تم اختصارها في سطر واحد، ودون أي عداد تديره بنفسك. اقرأ هذا السطر على النحو التالي: "لكل رقم من الأرقام التي تنتجها دالة `range(5)`، نفّذ الكتلة البرمجية مرة واحدة — وفي كل مرة، ضع ذلك الرقم في المتغير `number`."
يظهر هنا أمران بوضوح:
يبدأ العدّ من الصفر، والعدد 5 لا يظهر أبداً — هناك خمسة أرقام إجمالاً، لكنها تبدأ من 0 حتى 4. هذه هي نفس القاعدة التي تطبقها بايثون في كل مكان: تماماً كما يُستثنى فهرس النهاية في شرائح النصوص، يُستثنى أيضاً في range.
اسم المتغير number هو اختيارك أنت. يمكنك كتابة for i in range(5) بنفس الطريقة، ويُعد i الاسم المعتاد للعدادات البرمجية. ولكن عندما يكون للرقم معنى محدد، اختر اسماً يعبر عن هذا المعنى — فكتابة for student_number in range(30) تشرح نفسها بنفسها.
الأشكال الثلاثة لدالة range()
print("--- range(5) ---")
for i in range(5):
print(i, end=" ")
print()
print("--- range(2, 6) ---")
for i in range(2, 6):
print(i, end=" ")
print()
print("--- range(0, 10, 3) ---")
for i in range(0, 10, 3):
print(i, end=" ")
print()
print("--- range(5, 0, -1) ---")
for i in range(5, 0, -1):
print(i, end=" ")
print()--- range(5) ---
0 1 2 3 4
--- range(2, 6) ---
2 3 4 5
--- range(0, 10, 3) ---
0 3 6 9
--- range(5, 0, -1) ---
5 4 3 2 1القواعد:
range(stop)— يبدأ من0، وينتهي قبلstoprange(start, stop)— يبدأ منstart، وينتهي قبلstoprange(start, stop, step)— يتقدم بمقدار الخطوةstepفي كل مرة؛ والخطوة السالبة تعني العد تنازلياً إلى الخلف
تأمل المثالين الأخيرين بعناية. الكود range(0, 10, 3) يعطي 0 3 6 9 — الرقم التالي سيكون 12 وهو أكبر من 10، لذلك يتوقف. والكود range(5, 0, -1) يعطي 5 4 3 2 1 — الرقم 0 لا يظهر أبداً لأن النهاية مستثناة هنا أيضاً.
لماذا يُستثنى الحد الأخير؟ لأن ذلك يجعل الحسابات الرياضية في غاية البساطة. كم عدداً يوجد فيrange(0, 5)؟ الناتج هو5 - 0، أي خمسة أعداد. وفيrange(3, 8)؟ الناتج هو8 - 3، أي خمسة أعداد. ما عليك سوى الطرح لتحصل على العدد الإجمالي، دون حيرة في التساؤل عما إذا كان يجب عليك إضافة واحد أم لا. وإذا وضعت نطاقين متجاورين — مثلrange(0, 5)وrange(5, 10)— فلن تفوت أي رقم ولن تكرر أي رقم.
عندما تريد الأرقام من واحد إلى عشرة
يتكرر هذا الخطأ كثيراً لدرجة أنه يستحق قسماً خاصاً به:
print("Wrong — stops at 9:")
for i in range(1, 10):
print(i, end=" ")
print()
print("Right — includes 10:")
for i in range(1, 11):
print(i, end=" ")
print()Wrong — stops at 9:
1 2 3 4 5 6 7 8 9
Right — includes 10:
1 2 3 4 5 6 7 8 9 10القاعدة في سطر واحد: اكتب كقيمة توقف (stop) رقماً أكبر بواحد من آخر رقم تريده.
تجميع القيم — الآن بالطريقة الأسهل
total = 0
for number in range(1, 6):
total = total + number
print("Sum of 1 to 5:", total)Sum of 1 to 5: 15قارن هذا بنسخة while لنفس المهمة: لا يوجد عداد تنشئه، ولا عداد تزيده يدوياً، ولا خطر الوقوع في حلقة لانهائية. الشيء الوحيد الذي يجب الانتباه له هو أن المجمّع (accumulator) لا يزال بحاجة إلى أن يبدأ خارج الحلقة، تماماً كما في السابق.
التكرار على النصوص
لا تتنقل حلقة for عبر الأرقام فحسب — بل يمكنها المرور على النصوص حرفاً بحرف:
word = "Python"
for letter in word:
print(letter, end="-")
print()
vowel_count = 0
for letter in "programming":
if letter in "aeiou":
vowel_count = vowel_count + 1
print("Vowels:", vowel_count)P-y-t-h-o-n-
Vowels: 3لا توجد دالة range هنا لعدم الحاجة إليها — فالعبارة for letter in word تمر مباشرة على كل حرف. هذا أبسط بكثير من إجراء حسابات الفهارس يدوياً، ولا يعرّضك لخطر الوقوع في خطأ IndexError.
وعندما تحتاج إلى موضع الحرف (الفهرس) والحرف نفسه معاً، يمكنك استخدام دالة enumerate()، ولكن سنتناول ذلك بالتفصيل في درس القوائم.
break و continue يعملان هنا أيضاً
يعمل الأمران تماماً كما كانا يعملان في حلقة while:
for number in range(1, 20):
if number % 7 == 0:
print("First multiple of 7:", number)
breakFirst multiple of 7: 7الاختيار بين for و while
اطرح على نفسك سؤالاً واحداً: هل عدد التكرارات معروف قبل أن تبدأ الحلقة؟
إذا كانت الإجابة نعم، فاستخدم for:
- التكرار خمس مرات
- الانتقال من 1 إلى 100
- فحص كل حرف في كلمة
- القيام بعمل ما مع كل عنصر في قائمة
إذا كانت الإجابة لا، فاستخدم while:
- الاستمرار في السؤال حتى تصبح المدخلات صحيحة
- التكرار حتى يكتب المستخدم كلمة
quit - القراءة طالما بقيت أسطر في الملف
عند الشك، اختر for. والسبب بسيط: حلقة for مضمونة الانتهاء والتوقف، بينما حلقة while ليست كذلك. وحيثما يعمل كلاهما، فإن الأداة التي تقلل احتمالية الأخطاء هي دائماً الخيار الأفضل.
مثال متكامل
multiplication.py:
# Print a multiplication table, then a small summary
number = int(input("Which table? "))
upto = int(input("Up to? "))
print()
print(f"--- Table of {number} ---")
total = 0
for i in range(1, upto + 1):
result = number * i
total = total + result
print(f"{number} x {i:2} = {result:4}")
print()
print(f"Rows : {upto}")
print(f"Sum : {total}")
print(f"Average : {total / upto:.2f}")Which table? 7
Up to? 5
--- Table of 7 ---
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
Rows : 5
Sum : 105
Average : 21.00ثلاثة أشياء تستحق الانتباه. أولاً، range(1, upto + 1) — الوصول إلى upto استلزم كتابة رقم أكبر بواحد. ثانياً، {i:2} و {result:4} — داخل نصوص f-string يمكنك تحديد عرض المسافة التي يجب أن يشغلها الرقم، مما يحافظ على استقامة الأعمدة ومحاذاتها بدقة. ثالثاً، يبدأ total خارج الحلقة وينمو بداخلها — وهو نفس نمط المجمّع الذي رأيناه سابقاً.
واسأل نفسك سؤالاً واحداً: ماذا يحدث لو أجاب المستخدم بـ 0 عند السؤال عن Up to? سينتج عن range(1, 1) نطاق فارغ تماماً بدون أي أرقام، وبالتالي لن تنفذ الحلقة إطلاقاً — وعندها ستتسبب العملية total / upto في خطأ القسمة على صفر. هذا هو نفس الدرس المستفاد من الدرس السابق: قبل استخدام ما قامت الحلقة بتجميعه، تأكد من أنها قامت بتجميع أي شيء بالفعل.
حالات الخطأ الشائعة
الرقم الأخير مفقود ينتهي range(1, 10) عند الرقم 9. أضف واحداً إلى حد التوقف: range(1, 11).
TypeError: 'float' object cannot be interpreted as an integer لا تقبل دالة range() إلا أعداداً صحيحة. كتابة range(2.5) أو range(1, n / 2) لن تعمل — حوّل القيمة باستخدام int()، أو استخدم القسمة الصحيحة //.
SyntaxError: expected ':' نسيان النقطتين الرأسيتين في نهاية سطر for.
IndentationError: expected an indented block after 'for' statement السطر داخل الحلقة لم يُزح بمسافة بادئة.
الحلقة لم تنفّذ إطلاقاً نطاق range فارغ. ينتج عن range(5, 0) نطاق لا يحتوي على شيء — للعد تنازلياً تحتاج إلى الوسيط الثالث: range(5, 0, -1).
المجموع يساوي 0 بعد انتهاء الحلقة سطر total = 0 وُضع بالخطأ داخل الحلقة، مما يؤدي لإعادة ضبطه في كل دورة. يجب أن يكون خارج الحلقة.
متغير من داخل الحلقة مطلوب خارجها، ولكنه يسبب NameError كان نطاق range فارغاً، فلم تنفّذ الحلقة أبداً ولم يُنشأ المتغير أصلاً. امنحه قيمة ابتدائية قبل الحلقة.
Step 4 of 6 — Predict
Check your understanding
What does this loop print?
for i in range(1, 5):
print(i, end=" ")- A1 2 3 4
- B1 2 3 4 5
- C0 1 2 3 4
- D1 2 3
The third argument sets the step. What is the output?
for i in range(0, 10, 3):
print(i, end=" ")- A0 3 6 9
- B0 3 6 9 12
- C3 6 9
- D0 1 2 3 4 5 6 7 8 9
The intent was the sum of 1 to 10, which is 55. It prints 45. Why?
total = 0
for number in range(1, 10):
total = total + number
print("Sum of 1 to 10:", total)- A`range(1, 10)` finishes at `9` and leaves out `10` — it needs `range(1, 11)`
- B`total` was initialised outside the loop when it should be inside
- CUsing a `while` loop instead of `for` would give the right answer
- DIt should be `total + i` rather than `total + number`
Answering needs an account
Sign in to check your answers
The questions are above, and working them out in your head is the part that matters. Sign in to see the answers, the explanations and the three-level hints.
دورك الآن
اكتب ملفاً باسم stars.py يستقبل رقماً ويطبع مثلثاً من النجوم. إذا كان المدخل 5:
*
**
***
****
*****ثم أضف هذه المهام الثلاث:
- اطبع إجمالي عدد النجوم في الأسفل (15 للمدخل 5)
- اطبع المثلث مقلوباً أيضاً — خمس نجوم في الأعلى ونجمة واحدة في الأسفل
- اطبع نسخة تتخطى الصفوف ذات الأرقام الزوجية (استخدم
continue)
توجد طريقة سهلة للتحقق من المطلب الأول — احسب مجموع الأرقام من 1 إلى 5 يدوياً وانظر هل يتطابق برنامجك معه. وتذكر التعبير "*" * i؟ إنشاء صف من النجوم لا يحتاج إلى حلقة تكرارية إضافية داخل الحلقة الأولى.
Step 6 of 6
التحدي — the chapter quiz
عشرة أسئلة متدرجة من السهل إلى الصعب. الأسئلة الأخيرة صعبة عن قصد.
Sign in to take the quiz