أحمد حايس
الرئيسيةمن أناالدوراتالمدونةسوق الأوامرالمناهج والباقاتالشركاء
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • المناهج والباقات
  • سوق الأوامر
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالمناهجالمدونةالدخول
البرمجة بالعربي

الـ Recursion للمبتدئ: ليه دالة بتنادي نفسها بتوقّع برنامجك بـ RecursionError

مبتدئ10 يوليو 20264 دقائق قراءة
الـ Recursion للمبتدئ: ليه دالة بتنادي نفسها بتوقّع برنامجك بـ RecursionError

المستوى: مبتدئ. لو لسه في أول طريقك في البرمجة، وكلمة Recursion بتخضّك، المقال ده هيخلّيك تفهمها في أقل من 6 دقايق، وتعرف بالظبط ليه دالة بسيطة بتنادي نفسها ممكن تكسر البرنامج بخطأ اسمه RecursionError، وإزاي تتجنّبه.

الـ Recursion: لما الدالة تنادي نفسها

الفكرة كلها في جملة واحدة: الـ Recursion (الاستدعاء الذاتي) هو إن دالة تنادي نفسها عشان تحل نسخة أصغر من نفس المشكلة. المكسب إن الكود بيبقى قصير وأنيق في مسائل معيّنة. المشكلة: لو نسيت تقولها تقف امتى، البرنامج بيقع.

المشكلة باختصار

أغلب المبتدئين بيكتبوا دالة recursive صح، وتشتغل مع أرقام صغيرة، وبعدين تنفجر فجأة مع مدخل كبير. الرسالة اللي بتظهر: RecursionError: maximum recursion depth exceeded. ده مش عطل عشوائي، وله سبب دقيق هنفهمه دلوقتي بمثال بسيط ثم علميًا.

رسم توضيحي لمفهوم الـ Recursion على شكل إطارات متداخلة تصغر للداخل حتى تصل إلى حالة الأساس

خلّيك تفهمها الأول بعرائس الماتريوشكا

عندك عروسة خشب روسية (ماتريوشكا). بتفتحها، تلاقي جواها عروسة أصغر. بتفتح الصغيرة، تلاقي أصغر منها. وهكذا. لحد ما توصل لآخر عروسة صغيرة مصمتة، مش بتتفتح خالص. دي نقطة التوقف.

خلّينا نسمّي فعل افتح العروسة دالة. الدالة دي بتعمل حاجة واحدة: تفتح العروسة اللي قدامها، وبعدين تنادي نفسها على العروسة الأصغر اللي طلعت. العروسة المصمتة اللي مبتتفتحش هي اللي بتوقف السلسلة.

دلوقتي خُد عروسة معمولة غلط: كل ما تفتحها تلاقي جواها عروسة بنفس الحجم بالظبط، من غير ما توصل أبدًا لعروسة مصمتة. هتفضل تفتح للأبد. ده بالظبط اللي بيحصل للبرنامج لما تنسى نقطة التوقف.

التعريف العلمي بدقة

أي دالة recursive سليمة لازم يكون فيها جزئين: حالة الأساس (Base Case) وهي الشرط اللي بيوقف الاستدعاء ويرجع نتيجة مباشرة، والخطوة الاستدعائية (Recursive Step) اللي بتنادي الدالة نفسها على مدخل أصغر بحيث كل نداء يقرّب من حالة الأساس.

لو الخطوة الاستدعائية مش بتصغّر المدخل، أو حالة الأساس مش موجودة، الاستدعاء ميوقفش، وده مصدر المشكلة.

مثال كود شغّال

أشهر مثال: حساب المضروب (factorial). لاحظ حالة الأساس والخطوة الاستدعائية:

Python
def factorial(n):
    if n == 0:
        return 1
    return n * factorial(n - 1)

print(factorial(5))   # 120

ودلوقتي شوف اللي بيحصل لما ننسى حالة الأساس:

Python
import sys
print(sys.getrecursionlimit())   # 1000

def count_down(n):
    return count_down(n - 1)

count_down(100000)
# RecursionError: maximum recursion depth exceeded

الفرق سطر واحد: غياب الشرط اللي يوقف السلسلة.

مخطط يقارن مكدس استدعاء سليم يرجع من الاستدعاءات إلى حالة الأساس مقابل مكدس يتجاوز الحد

ليه بيحصل الخطأ ده؟ قصة المكدس

كل مرة الدالة تنادي نفسها، النظام بيحجز شوية ذاكرة اسمها إطار (Stack Frame) عشان يفتكر المتغيرات المحلية ومكان الرجوع. الإطارات دي بتتركم فوق بعضها في مكدس الاستدعاء. لما الدالة توصل لحالة الأساس وترجع، الإطارات بتتشال واحد واحد.

المشكلة إن المكدس محدود. بايثون بيحط سقف افتراضي حوالي 1000 نداء متداخل. لو عدّيته من غير رجوع، بايثون بيوقفك بـ RecursionError قبل ما الذاكرة كلها تتآكل.

سيناريو واقعي: دالة recursive بتمشي على شجرة مجلدات فيها تفريعات أعمق من ألف مستوى (بيحصل مع JSON عميق أو روابط رمزية دايرة) هتضرب الخطأ، بينما نسخة بحلقة while ومكدس يدوي هتكمّل عادي.

الـ trade-off: Recursion ولا حلقة؟

الـ Recursion بتكسب كود أوضح وأقصر في المسائل المتداخلة (الأشجار، البحث في المجلدات)، بتخسر ذاكرة على المكدس بمقدار O(n) إطارات زائد بطء بسيط. الحلقة بتكسب ذاكرة ثابتة وسرعة أعلى، بتخسر شوية وضوح. القاعدة: لو العمق بالعشرات فالـ recursion آمنة، لو ممكن يوصل للمئات أو الآلاف فكّر مرتين.

متى لا تستخدم الـ Recursion

ابعد عنها لما العمق ممكن يعدّي المئات، أو لما تقدر تحلها بحلقة بسيطة، أو في كود حرج للأداء داخل حلقات ساخنة. الافتراض هنا مبني على بايثون بحدّه 1000؛ لغات تانية ليها حدود مختلفة، وبعضها بيعمل Tail Call Optimization وبايثون مش منهم.

الخطوة التالية

افتح أي دالة recursive عندك ودوّر على سطر حالة الأساس. لو مش لاقيه، ده باج مستني يحصل. وبعدين انسخ دالة factorial اللي فوق، غيّر شرط التوقف من n == 0 لـ n == -1 ونادِها بـ factorial(5)، وهتشوف RecursionError بعينك.

المصادر

  • توثيق بايثون: docs.python.org/3/library/sys.html#sys.setrecursionlimit
  • مسرد بايثون: docs.python.org/3/glossary.html
  • Real Python: realpython.com/python-recursion
  • Wikipedia Call stack: en.wikipedia.org/wiki/Call_stack
  • Wikipedia Stack overflow: en.wikipedia.org/wiki/Stack_overflow

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة