المستوى: مبتدئ. لو لسه في أول طريقك في البرمجة، وكلمة Recursion بتخضّك، المقال ده هيخلّيك تفهمها في أقل من 6 دقايق، وتعرف بالظبط ليه دالة بسيطة بتنادي نفسها ممكن تكسر البرنامج بخطأ اسمه RecursionError، وإزاي تتجنّبه.
الـ Recursion: لما الدالة تنادي نفسها
الفكرة كلها في جملة واحدة: الـ Recursion (الاستدعاء الذاتي) هو إن دالة تنادي نفسها عشان تحل نسخة أصغر من نفس المشكلة. المكسب إن الكود بيبقى قصير وأنيق في مسائل معيّنة. المشكلة: لو نسيت تقولها تقف امتى، البرنامج بيقع.
المشكلة باختصار
أغلب المبتدئين بيكتبوا دالة recursive صح، وتشتغل مع أرقام صغيرة، وبعدين تنفجر فجأة مع مدخل كبير. الرسالة اللي بتظهر: RecursionError: maximum recursion depth exceeded. ده مش عطل عشوائي، وله سبب دقيق هنفهمه دلوقتي بمثال بسيط ثم علميًا.
خلّيك تفهمها الأول بعرائس الماتريوشكا
عندك عروسة خشب روسية (ماتريوشكا). بتفتحها، تلاقي جواها عروسة أصغر. بتفتح الصغيرة، تلاقي أصغر منها. وهكذا. لحد ما توصل لآخر عروسة صغيرة مصمتة، مش بتتفتح خالص. دي نقطة التوقف.
خلّينا نسمّي فعل افتح العروسة دالة. الدالة دي بتعمل حاجة واحدة: تفتح العروسة اللي قدامها، وبعدين تنادي نفسها على العروسة الأصغر اللي طلعت. العروسة المصمتة اللي مبتتفتحش هي اللي بتوقف السلسلة.
دلوقتي خُد عروسة معمولة غلط: كل ما تفتحها تلاقي جواها عروسة بنفس الحجم بالظبط، من غير ما توصل أبدًا لعروسة مصمتة. هتفضل تفتح للأبد. ده بالظبط اللي بيحصل للبرنامج لما تنسى نقطة التوقف.
التعريف العلمي بدقة
أي دالة recursive سليمة لازم يكون فيها جزئين: حالة الأساس (Base Case) وهي الشرط اللي بيوقف الاستدعاء ويرجع نتيجة مباشرة، والخطوة الاستدعائية (Recursive Step) اللي بتنادي الدالة نفسها على مدخل أصغر بحيث كل نداء يقرّب من حالة الأساس.
لو الخطوة الاستدعائية مش بتصغّر المدخل، أو حالة الأساس مش موجودة، الاستدعاء ميوقفش، وده مصدر المشكلة.
مثال كود شغّال
أشهر مثال: حساب المضروب (factorial). لاحظ حالة الأساس والخطوة الاستدعائية:
def factorial(n):
if n == 0:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120
ودلوقتي شوف اللي بيحصل لما ننسى حالة الأساس:
import sys
print(sys.getrecursionlimit()) # 1000
def count_down(n):
return count_down(n - 1)
count_down(100000)
# RecursionError: maximum recursion depth exceeded