Master

When recursion is too deep

Recursion has a depth limit. When the input nests deeper than the limit, you hit a RecursionError. The fixes are to raise the limit, go bottom-up, or manage your own stack.

What you will see

5000050000

About 3 min of reading

Try It

Handle a recursion that is too deep.

1

Catch a RecursionError.

import sys sys.setrecursionlimit(50) def f(n): if n == 0: return 0 return f(n - 1) try: f(100) except RecursionError: print(sys.getrecursionlimit())

Before you run it, say out loud what it will print. Then open the answer.

What it prints
50
2

Iterative nested sum.

def total(a): stack = list(a) s = 0 while stack: x = stack.pop() if isinstance(x, list): stack.extend(x) else: s += x return s print(total([1, [2, [3]]]))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
6
3

Iterative tree size.

def size(root): stack = [root] n = 0 while stack: node = stack.pop() if node is None: continue n += 1 stack.append(node.get("left")) stack.append(node.get("right")) return n tree = {"v": 1, "left": {"v": 2}, "right": {"v": 3}} print(size(tree))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
3
4

Loop sum to 100000.

n, acc = 100000, 0 while n: acc += n n -= 1 print(acc)

Before you run it, say out loud what it will print. Then open the answer.

What it prints
5000050000

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

Recursion depth is capped. Deep inputs raise RecursionError; fix them by looping, going bottom-up, or keeping your own stack.
1 nesting too deep
↓
2 RecursionError raised
↓
3 raise limit or loop
↓
4 own stack in memory
Line by line

Read the first example one line at a time. A line that prints shows what appears on screen; the rest set things up quietly.

import sys sets nothing on screen
sys.setrecursionlimit(50) sets nothing on screen
def f(n): sets nothing on screen
if n == 0: sets nothing on screen
return 0 sets nothing on screen
return f(n - 1) sets nothing on screen
try: sets nothing on screen
f(100) sets nothing on screen
except RecursionError: sets nothing on screen
print(sys.getrecursionlimit()) 50
Why this works
Limit is a guard

The recursion limit stops runaway calls before the real stack crashes. Raising it trades safety for reach, not unlimited memory.

Explicit stack is the escape

Any recursion can be rewritten with your own stack in a loop. That removes the depth limit at the cost of clearer code.

Examples

Hit the limit

import sys
sys.setrecursionlimit(50)
def f(n):
    if n == 0:
        return 0
    return f(n - 1)
try:
    f(100)
except RecursionError:
    print(sys.getrecursionlimit())

A depth past the limit raises RecursionError. The limit is a guard, not free memory.

Raise the limit

import sys
sys.setrecursionlimit(10000)
def f(n):
    if n == 0:
        return 0
    return f(n - 1)
print(f(1000))

Raising the limit lets deeper calls run. Too high and the real stack still crashes.

Own stack instead

def total(a):
    stack = list(a)
    s = 0
    while stack:
        x = stack.pop()
        if isinstance(x, list):
            stack.extend(x)
        else:
            s += x
    return s
print(total([1, [2, [3]]]))

Push the work onto a list yourself. No call frames, so no depth limit.

Iterative tree walk

def size(root):
    stack = [root]
    n = 0
    while stack:
        node = stack.pop()
        if node is None:
            continue
        n += 1
        stack.append(node.get("left"))
        stack.append(node.get("right"))
    return n
tree = {"v": 1, "left": {"v": 2}, "right": {"v": 3}}
print(size(tree))

An explicit stack walks the tree with no recursion. The stack lives in memory.

Depth of a chain

import sys
print(sys.getrecursionlimit())

The default limit is around a thousand. A linked chain longer than that breaks a recursive walk.

Tail loop is safest

n, acc = 100000, 0
while n:
    acc += n
    n -= 1
print(acc)

For a long flat count, a loop has no depth limit at all. That is the safe default.

Memo keeps depth

import sys
sys.setrecursionlimit(2000)
from functools import lru_cache
@lru_cache(maxsize=None)
def f(n):
    if n < 2:
        return n
    return f(n - 1) + f(n - 2)
print(f(500))

A cache removes repeated work but not the depth of the first chain. Depth still counts.

Balance the tree

def height(node):
    if node is None:
        return 0
    return 1 + max(height(node.get("left")), height(node.get("right")))
tree = {"v": 2, "left": {"v": 1}, "right": {"v": 3}}
print(height(tree))

A balanced tree has log depth, so recursion is safe. A skewed one has linear depth.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Top-down versus bottom-up
Previous Lesson
Top-down versus bottom-up
Next Lesson
Parsing nested text
Parsing nested text →