Don’t Use Recursion in Python Anymore — Here’s Why (And What to Do Instead)

Python’s recursion isn’t what you think.

Don’t Use Recursion in Python Anymore — Here’s Why (And What to Do Instead)
Photo by Mike Smith on Unsplash

You’ve been solving problems the hard way — and Python’s not happy about it.

Don’t Use Recursion in Python Anymore — Here’s Why (And What to Do Instead)

You’ve probably heard this before: Recursion is elegant. Recursion is powerful.
And in many languages, it absolutely is.

But in Python? Recursion can be a trap.

Sure, it’s a go-to tool when learning algorithms. It feels mathematically beautiful. You write a function that calls itself, and voila — it looks like you know what you’re doing.

But if you’ve ever hit a RecursionError: maximum recursion depth exceeded, you’ve already felt the edge of the sword.

Python isn’t optimized for deep recursion. And once you start building real-world applications — anything beyond toy problems — you’ll quickly realize that recursion is more liability than magic.


Why Recursion Falls Flat in Python

Let’s get right to it: Python has a recursion limit.
By default, that’s 1,000 function calls deep.

This means if your recursive function goes too far — say, while processing a large tree or doing a depth-first search on a huge graph — your program crashes. Hard.

Here’s what happens under the hood:

  • Each function call in Python consumes stack space.
  • Python does not perform tail call optimization (a compiler optimization that languages like Scheme or Scala use to reuse stack frames).
  • As a result, deeply recursive calls quickly blow up the call stack.

Let’s illustrate that with an innocent-looking function:

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

Run this, and you’ll get:

RecursionError: maximum recursion depth exceeded in comparison

That’s your elegant recursion collapsing on itself.

But Recursion Is Clean, Right?

Sure, recursion can make code look clean — for small problems:

def fib(n): 
    if n <= 1: 
        return n 
    return fib(n - 1) + fib(n - 2)

It’s short. It’s readable. It’s also horribly inefficient.

This implementation is exponential in time complexity (O(2^n)). It recalculates the same values again and again.

Try calling fib(40), and your laptop fans will start to sing.

Iteration Is Boring — But It Works

You don’t need recursion to solve recursive problems. You need a stack.

And Python lists make great stacks.

Here’s how to rewrite factorial iteratively:

def factorial_iterative(n): 
    result = 1 
    for i in range(2, n + 1): 
        result *= i 
    return result

Much faster. No risk of a recursion crash. Just good old for-loops.

And the Fibonacci example?

def fib_iterative(n): 
    if n <= 1: 
        return n 
    prev, curr = 0, 1 
    for _ in range(2, n + 1): 
        prev, curr = curr, prev + curr 
    return curr

Runs instantly, even for large n.

The Hidden Cost of Recursion in Python

If performance isn’t enough to sway you, consider these other downsides:

1. Harder to Debug

Recursive call stacks are difficult to follow in real-time. You lose track of where you are — and what variables hold.

2. Memory Overhead

Every recursive call creates a new stack frame. That’s a lot of memory wasted when iteration could do the same with one frame.

3. Lack of Tail Call Optimization

Many functional languages automatically optimize tail-recursive calls into loops. Python doesn’t — by design. Guido van Rossum (Python’s creator) deliberately left it out to keep debugging simple and explicit.

“If you want to write efficient code, use iteration.” — Python community wisdom

So When Can You Use Recursion?

To be fair, recursion isn’t always evil in Python. It’s acceptable when:

  • The depth of recursion is guaranteed to be shallow
  • You’re writing code for educational purposes
  • You’re working with functional-style problems (e.g., quicksort on small arrays)

Or when recursion actually clarifies the logic better than iteration — and performance isn’t a concern.

But for production? Recursion is often a ticking time bomb.

Practical Tip: Simulate Recursion With an Explicit Stack

Let’s say you need to traverse a binary tree. Recursion is natural here — but you can do it iteratively with an explicit stack.

def inorder_traversal(root): 
    stack = [] 
    current = root 
    result = [] 
 
    while stack or current: 
        while current: 
            stack.append(current) 
            current = current.left 
        current = stack.pop() 
        result.append(current.val) 
        current = current.right 
 
    return result

Cleaner, safer, and infinitely scalable.

Real-World Case Study: DFS in a Graph

Here’s a quick example from a web scraping script I wrote.

I used DFS to traverse pages and avoid cycles. The recursive version kept hitting limits. The fix?

def dfs_iterative(graph, start): 
    visited = set() 
    stack = [start] 
 
    while stack: 
        node = stack.pop() 
        if node not in visited: 
            visited.add(node) 
            stack.extend(graph[node] - visited) 
     
    return visited

Boom. Scales to thousands of nodes. No crash. No problem.


Conclusion: Stop Using Recursion as a Default

Python isn’t designed for heavy recursion. If you’re reaching for recursion as your go-to pattern, stop and ask:

Can this be done with iteration?

Chances are, yes. And it’ll be faster, safer, and easier to maintain.

So the next time someone shows off a fancy recursive solution, impress them with your iterative, robust, Pythonic alternative.


Recursion is like a beautiful sports car — it looks great but crashes easily. Iteration is your dependable all-terrain vehicle. For Python, go off-road.

Photo by Harry Holder on Unsplash