Recursion Explained With Simple Examples
Recursion is when a function calls itself. That definition is short, but it can feel strange the first time you see it. Why would a function call itself? Wouldn't it run forever? It can run forever if you write it incorrectly. But when recursion is written carefully, it is a clean way to solve problems that can be broken into smaller versions of the same problem. The key is understanding two parts:
- the base case
- the recursive case Once those two ideas click, recursion becomes much less mysterious.
The Mental Model
A recursive function solves a problem by saying:
- If the problem is simple enough, return the answer.
- Otherwise, solve a smaller version of the same problem. The simple-enough case is called the **base case**. The smaller-version step is called the **recursive case**. Without a base case, recursion does not know when to stop.
A Countdown Example
Here is a simple recursive countdown:
def countdown(number):
if number == 0:
print("done")
return
print(number)
countdown(number - 1)
Usage:
countdown(3)
Output: ```plain text 3 2 1 done
The base case is:
```python
if number == 0:
The recursive case is:
countdown(number - 1)
Each call gets closer to the base case. That is the most important rule in recursion.
Factorial Example
Factorial is a classic recursion example. `5!` means: ```plain text 5 * 4 * 3 * 2 * 1
We can define it recursively:
```plain text
factorial(5) = 5 * factorial(4)
factorial(4) = 4 * factorial(3)
factorial(3) = 3 * factorial(2)
factorial(2) = 2 * factorial(1)
factorial(1) = 1
In Python:
def factorial(number):
if number == 1:
return 1
return number * factorial(number - 1)
Usage:
print(factorial(5)) # 120
Again, there is a base case and a recursive case.
The Call Stack
Recursion works because function calls are stored on the call stack. When `factorial(5)` calls `factorial(4)`, Python needs to remember that `factorial(5)` is waiting for a result. The stack builds up: ```plain text factorial(1) factorial(2) factorial(3) factorial(4) factorial(5)
When the base case returns, the calls unwind:
```plain text
factorial(1) returns 1
factorial(2) returns 2 * 1
factorial(3) returns 3 * 2
factorial(4) returns 4 * 6
factorial(5) returns 5 * 24
That final result is `120`. This is why understanding stacks helps with recursion.
Recursion With Lists
Here is a recursive function to sum a list:
def recursive_sum(numbers):
if not numbers:
return 0
return numbers[0] + recursive_sum(numbers[1:])
Usage:
print(recursive_sum([1, 2, 3, 4])) # 10
The base case is an empty list. The recursive case adds the first number to the sum of the rest. This is a nice mental model, but in real Python, slicing creates new lists, so an iterative version may be more efficient.
def iterative_sum(numbers):
total = 0
for number in numbers:
total += number
return total
Recursion is not always the best implementation. It is a way to think about certain problems.
Common Mistakes
Mistake 1: Forgetting the base case
Without a base case, recursion keeps going until the program crashes.
def broken():
broken()
Python will eventually raise a recursion error.
Mistake 2: Not moving toward the base case
This has a base case, but still fails:
def countdown(number):
if number == 0:
return
countdown(number)
The value never changes, so the function never gets closer to stopping.
Mistake 3: Using recursion when a loop is clearer
Some problems are naturally recursive. Others are simpler with a loop. If a loop is easier to read and performs well, use the loop. Recursion is a tool, not a requirement.
Where This Shows Up in Real Projects
Recursion appears naturally in problems with nested structures:
- file trees
- menu trees
- comments and replies
- organization charts
- nested JSON
- tree traversal
- backtracking problems For example, if you need to render nested categories, recursion can be a clean fit because each category may contain smaller categories.
Key Takeaways
- Recursion is when a function calls itself.
- Every recursive function needs a base case.
- The recursive case should move toward the base case.
- The call stack tracks unfinished function calls.
- Recursion is useful for nested or self-similar problems.
Loops are sometimes simpler and more efficient.
Related Articles
Stacks Explained With Real Examples
- Big O Notation Explained With Python Examples
- Linked Lists Explained From Scratch