الدرس 6

الحلقات

الوحدة 2: التحكم في التدفق وقت القراءة: 18 دقيقة

لماذا نستخدم الحلقات؟

الحلقات تسمح لك بتنفيذ كتلة من الكود عدة مرات. بدلاً من كتابة كود متكرر، الحلقات تساعدك على أتمتة المهام المتكررة بكفاءة.

حلقة for

تُستخدم للتكرار على تسلسل (قائمة، نص، نطاق، إلخ):

Python
# حلقة for أساسية مع قائمة
فواكه = ["تفاح", "موز", "كرز"]

for فاكهة in فواكه:
    print(f"أحب {فاكهة}")

# الناتج:
# أحب تفاح
# أحب موز
# أحب كرز

# التكرار على نص
for حرف in "بايثون":
    print(حرف, end=" ")  # ب ا ي ث و ن

print()  # سطر جديد

# استخدام range() لتسلسلات الأرقام
for ع in range(5):
    print(ع, end=" ")  # 0 1 2 3 4

دالة range()

تُنشئ تسلسلاً من الأرقام:

Python
# range(نهاية) - من 0 إلى نهاية-1
for ع in range(5):
    print(ع, end=" ")  # 0 1 2 3 4
print()

# range(بداية, نهاية) - من بداية إلى نهاية-1
for ع in range(2, 7):
    print(ع, end=" ")  # 2 3 4 5 6
print()

# range(بداية, نهاية, خطوة) - مع زيادة
for ع in range(0, 10, 2):
    print(ع, end=" ")  # 0 2 4 6 8
print()

# العد للخلف
for ع in range(5, 0, -1):
    print(ع, end=" ")  # 5 4 3 2 1
print()

# عملي: طباعة جدول الضرب
الرقم = 7
print(f"\nجدول ضرب {الرقم}:")
for ع in range(1, 11):
    print(f"{الرقم} × {ع} = {الرقم * ع}")

التكرار مع الفهرس

أحياناً تحتاج الفهرس والقيمة معاً:

Python
# الطريقة 1: استخدام range مع len
ألوان = ["أحمر", "أخضر", "أزرق"]

for ع in range(len(ألوان)):
    print(f"الفهرس {ع}: {ألوان[ع]}")

# الطريقة 2: استخدام enumerate (مفضلة!)
for فهرس, لون in enumerate(ألوان):
    print(f"الفهرس {فهرس}: {لون}")

# البدء من 1
for فهرس, لون in enumerate(ألوان, start=1):
    print(f"اللون {فهرس}: {لون}")

# الناتج:
# اللون 1: أحمر
# اللون 2: أخضر
# اللون 3: أزرق
أفضل الممارسات

استخدم enumerate() بدلاً من range(len()) عندما تحتاج الفهرس والقيمة معاً. إنها أكثر بايثونية وقابلية للقراءة!

حلقة while

تُنفذ طالما الشرط صحيح:

Python
# حلقة while أساسية
العداد = 0

while العداد < 5:
    print(f"العداد: {العداد}")
    العداد += 1  # لا تنسَ التحديث!

# العد التنازلي
العد_التنازلي = 5
while العد_التنازلي > 0:
    print(العد_التنازلي)
    العد_التنازلي -= 1
print("انطلاق!")

# التحقق من إدخال المستخدم (مفاهيمي)
كلمة_السر = "سري"
المحاولات = 3

while المحاولات > 0:
    # في الكود الحقيقي: إدخال = input("أدخل كلمة السر: ")
    إدخال = "خطأ"  # إدخال محاكى

    if إدخال == كلمة_السر:
        print("تم منح الوصول!")
        break
    else:
        المحاولات -= 1
        print(f"كلمة سر خاطئة. {المحاولات} محاولات متبقية.")
        if المحاولات == 0:
            break  # خروج للعرض

print("انتهت عملية تسجيل الدخول")
تحذير: الحلقات اللانهائية

تأكد دائماً أن حلقة while لديها طريقة للإنهاء. نسيان تحديث متغير الشرط يُنشئ حلقة لانهائية!

# خطر: حلقة لانهائية!
# while True:
#     print("هذا لن يتوقف أبداً!")

# آمن: لديها شرط خروج
while True:
    # افعل شيئاً
    break  # هذا يخرج من الحلقة

break و continue

للتحكم في تنفيذ الحلقة:

Python
# break - يخرج من الحلقة فوراً
print("إيجاد أول رقم زوجي:")
for رقم in [1, 3, 5, 4, 7, 8]:
    if رقم % 2 == 0:
        print(f"وجدت: {رقم}")
        break
    print(f"أفحص {رقم}...")

# الناتج:
# أفحص 1...
# أفحص 3...
# أفحص 5...
# وجدت: 4

print("\n" + "="*30 + "\n")

# continue - يتخطى للتكرار التالي
print("طباعة الأرقام الفردية فقط:")
for رقم in range(10):
    if رقم % 2 == 0:
        continue  # تخطي الأرقام الزوجية
    print(رقم, end=" ")  # 1 3 5 7 9

print("\n")

# مثال عملي: تخطي البيانات غير الصالحة
بيانات = [10, -5, 20, None, 30, "خطأ", 40]
المجموع = 0

for عنصر in بيانات:
    if عنصر is None or not isinstance(عنصر, (int, float)):
        continue
    if عنصر < 0:
        continue
    المجموع += عنصر

print(f"مجموع الأرقام الموجبة الصالحة: {المجموع}")  # 100

جملة else في الحلقات

بايثون لديها جملة else للحلقات تُنفذ عندما تكتمل الحلقة بشكل طبيعي:

Python
# else تُنفذ إذا اكتملت الحلقة بدون break
أرقام = [1, 3, 5, 7, 9]

for رقم in أرقام:
    if رقم % 2 == 0:
        print(f"وجدت زوجي: {رقم}")
        break
else:
    print("لم أجد أي رقم زوجي")  # هذا يُطبع

# else لا تُنفذ إذا تم تفعيل break
أرقام = [1, 3, 4, 7, 9]

for رقم in أرقام:
    if رقم % 2 == 0:
        print(f"وجدت زوجي: {رقم}")
        break
else:
    print("لم أجد أي رقم زوجي")  # هذا لا يُطبع

# عملي: البحث مع رسالة غير موجود
def ابحث_عن_مستخدم(المستخدمون, الهوية_المطلوبة):
    for مستخدم in المستخدمون:
        if مستخدم["id"] == الهوية_المطلوبة:
            print(f"وجدت: {مستخدم['الاسم']}")
            break
    else:
        print(f"المستخدم {الهوية_المطلوبة} غير موجود")

المستخدمون = [
    {"id": 1, "الاسم": "أحمد"},
    {"id": 2, "الاسم": "سارة"},
    {"id": 3, "الاسم": "محمد"}
]

ابحث_عن_مستخدم(المستخدمون, 2)  # وجدت: سارة
ابحث_عن_مستخدم(المستخدمون, 5)  # المستخدم 5 غير موجود

الحلقات المتداخلة

حلقات داخل حلقات للبيانات متعددة الأبعاد:

Python
# حلقة متداخلة أساسية
for ص in range(3):
    for س in range(3):
        print(f"({ص}, {س})", end=" ")
    print()  # سطر جديد بعد كل صف

# الناتج:
# (0, 0) (0, 1) (0, 2)
# (1, 0) (1, 1) (1, 2)
# (2, 0) (2, 1) (2, 2)

# جدول الضرب
print("\nجدول الضرب:")
print("   ", end="")
for ع in range(1, 6):
    print(f"{ع:4}", end="")
print("\n" + "-" * 25)

for ص in range(1, 6):
    print(f"{ص} |", end="")
    for س in range(1, 6):
        print(f"{ص*س:4}", end="")
    print()

# طباعة نمط
print("\nنمط المثلث:")
for ص in range(1, 6):
    print("* " * ص)

# الناتج:
# *
# * *
# * * *
# * * * *
# * * * * *

التكرار على أنواع بيانات مختلفة

Python
# التكرار على القاموس
شخص = {"الاسم": "أحمد", "العمر": 30, "المدينة": "الرياض"}

# المفاتيح فقط (الافتراضي)
for مفتاح in شخص:
    print(مفتاح)

# القيم فقط
for قيمة in شخص.values():
    print(قيمة)

# أزواج مفتاح-قيمة
for مفتاح, قيمة in شخص.items():
    print(f"{مفتاح}: {قيمة}")

# قائمة من القواميس
طلاب = [
    {"الاسم": "أحمد", "الدرجة": 90},
    {"الاسم": "سارة", "الدرجة": 85},
    {"الاسم": "محمد", "الدرجة": 92}
]

for طالب in طلاب:
    print(f"{طالب['الاسم']}: {طالب['الدرجة']}")

# قوائم متعددة مع zip
الأسماء = ["أحمد", "سارة", "محمد"]
الأعمار = [25, 30, 35]
المدن = ["الرياض", "جدة", "الدمام"]

for اسم, عمر, مدينة in zip(الأسماء, الأعمار, المدن):
    print(f"{اسم} عمره {عمر} من {مدينة}")

فهم القوائم (معاينة)

طريقة بايثونية لإنشاء القوائم باستخدام الحلقات:

Python
# الحلقة التقليدية
مربعات = []
for س in range(10):
    مربعات.append(س ** 2)
print(مربعات)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# فهم القائمة (نفس النتيجة)
مربعات = [س ** 2 for س in range(10)]
print(مربعات)

# مع شرط
مربعات_زوجية = [س ** 2 for س in range(10) if س % 2 == 0]
print(مربعات_زوجية)  # [0, 4, 16, 36, 64]

# تحويل البيانات
أسماء = ["أحمد", "سارة", "محمد"]
أسماء_كبيرة = [اسم.upper() for اسم in أسماء]
print(أسماء_كبيرة)  # ['أحمد', 'سارة', 'محمد']

تحدي: FizzBuzz

اكتب برنامجاً يطبع الأرقام 1-30، لكن:

  • لمضاعفات 3، اطبع "Fizz" بدلاً منها
  • لمضاعفات 5، اطبع "Buzz" بدلاً منها
  • لمضاعفات كل من 3 و 5، اطبع "FizzBuzz"
أظهر الحل
for رقم in range(1, 31):
    if رقم % 3 == 0 and رقم % 5 == 0:
        print("FizzBuzz")
    elif رقم % 3 == 0:
        print("Fizz")
    elif رقم % 5 == 0:
        print("Buzz")
    else:
        print(رقم)

تحدي: إيجاد الأعداد الأولية

اكتب برنامجاً يجد جميع الأعداد الأولية بين 2 و 50.

العدد الأولي يقبل القسمة فقط على 1 وعلى نفسه.

أظهر الحل
print("الأعداد الأولية بين 2 و 50:")

for رقم in range(2, 51):
    أولي = True

    # تحقق إذا كان الرقم يقبل القسمة على أي رقم من 2 إلى جذره
    for ع in range(2, int(رقم ** 0.5) + 1):
        if رقم % ع == 0:
            أولي = False
            break

    if أولي:
        print(رقم, end=" ")

# الناتج: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

تحدي: لعبة تخمين الأرقام

أنشئ لعبة تخمين أرقام حيث:

  • الرقم السري هو 42
  • المستخدم لديه 5 محاولات
  • أعطِ تلميحات: "أعلى" أو "أقل"
  • أظهر المحاولات المتبقية
أظهر الحل
السري = 42
الحد_الأقصى = 5
المحاولات = 0
التخمينات = [50, 30, 40, 45, 42]  # إدخال محاكى

print("خمن الرقم بين 1 و 100!")

while المحاولات < الحد_الأقصى:
    # في الكود الحقيقي: التخمين = int(input("تخمينك: "))
    التخمين = التخمينات[المحاولات]  # إدخال محاكى
    المحاولات += 1
    المتبقي = الحد_الأقصى - المحاولات

    print(f"خمنت: {التخمين}")

    if التخمين == السري:
        print(f"مبروك! نجحت في {المحاولات} محاولات!")
        break
    elif التخمين < السري:
        print(f"أقل! {المتبقي} محاولات متبقية.")
    else:
        print(f"أعلى! {المتبقي} محاولات متبقية.")
else:
    print(f"انتهت اللعبة! الرقم كان {السري}")

النقاط الرئيسية

ملخص
  • حلقات for تتكرر على التسلسلات (قوائم، نصوص، نطاقات)
  • range(بداية, نهاية, خطوة) تُنشئ تسلسلات أرقام
  • enumerate() تعطي الفهرس والقيمة معاً
  • حلقات while تعمل طالما الشرط True
  • break تخرج من الحلقة فوراً
  • continue تتخطى للتكرار التالي
  • else في الحلقات تُنفذ عند اكتمال الحلقة بشكل طبيعي
  • zip() تتكرر على تسلسلات متعددة معاً
  • فهم القوائم يوفر صياغة حلقات موجزة

في الدرس القادم، سنتعلم عن التحكم المتقدم في الحلقات والدوال لكتابة كود أنظف وقابل لإعادة الاستخدام!