A function that calls itself is recursive. It's like looking up a word in a dictionary and finding another word you need to look up — which sends you to another word — until you find one you understand.
Example: Factorial
def factorial(n):
# Base case: 0! = 1! = 1
if n <= 1:
return 1
# Recursive case: n! = n * (n-1)!
return n * factorial(n - 1)
Trace for factorial(3):
factorial(3)
→ 3 * factorial(2)
→ 3 * 2 * factorial(1)
→ 3 * 2 * 1
→ 6
Each recursive call is pushed onto the call stack. When the base case is reached, the calls are popped off in reverse order (Last In, First Out).
Many problems become elegant and simple when solved recursively. Let's look at some classic examples.
def binary_search(items, target, left, right):
if left > right:
return -1 # Base case: empty range
mid = (left + right) // 2
if items[mid] == target:
return mid # Base case: found
elif items[mid] < target:
return binary_search(items, target, mid + 1, right)
else:
return binary_search(items, target, left, mid - 1)
Each recursive call searches a smaller half of the list. The base cases are either finding the target or the range becoming empty.
| Criteria | Recursion | Iteration (Loops) |
|---|---|---|
| Code clarity | Elegant for tree/graph problems | Simple for linear problems |
| Memory | Uses call stack — risk of stack overflow | Constant extra memory |
| Performance | Slower — function call overhead | Faster — no overhead |
| Use case | Tree traversal, divide-and-conquer | Array/list processing |