Python Recursion Limit: Setting and Handling Deep Recursion
python recursion limit: Understand Python's recursion limit, how to check and adjust it, and why iterative alternatives are often safer for deep recursion.
When a Python function calls itself repeatedly, the interpreter tracks the current call stack. Each recursive call consumes stack memory, and Python enforces a maximum depth to prevent the process from crashing. That cap is the python recursion limit, and it is the reason you see RecursionError: maximum recursion depth exceeded in long-running recursive code.
Understanding the Recursion Limit
Python's recursion limit is a safety mechanism. It prevents a runaway recursive function from exhausting the C stack, which would cause a hard crash rather than a catchable exception. The limit is stored in the sys module as sys.getrecursionlimit() and defaults to 1000 in CPython. That number includes the initial call frame, so a function that calls itself 999 times is at the edge.
The limit applies to all recursive calls, not just direct self-recursion. Mutual recursion—where a() calls b() and b() calls a()—counts against the same stack depth. Even indirect recursion through callbacks or decorators can hit the limit if the chain is deep enough.
Checking the Current Recursion Limit
You can inspect the current limit with sys.getrecursionlimit():
import sys print(sys.getrecursionlimit())
On a typical CPython installation, this prints 1000. The value is configurable at runtime, but changing it affects the entire process. It is not a per-thread or per-function setting.
What Happens When You Exceed the Limit
When a recursive call would push the stack beyond the limit, Python raises a RecursionError. This is a subclass of RuntimeError, so it is catchable, but catching it is rarely a good idea unless you have a specific recovery plan.
def countdown(n): print(n) countdown(n - 1) countdown(1000)
Running this produces a long output followed by RecursionError. The traceback shows the repeated calls, making the cause clear. The error is raised before the actual C stack is exhausted, so the process remains stable and can continue after handling the exception.
Increasing the Recursion Limit with sys.setrecursionlimit
You can raise the limit using sys.setrecursionlimit(). For example, to allow 5000 frames:
import sys sys.setrecursionlimit(5000)
This is a global change. Once set, it applies to all code in the interpreter until changed again. The new limit must be greater than the current stack depth, or Python raises a RecursionError immediately.
A common pattern is to set a higher limit in a script that performs a known deep recursion, such as traversing a deeply nested JSON structure:
import sys import json sys.setrecursionlimit(10000) def walk(node): if isinstance(node, dict): for value in node.values(): walk(value) elif isinstance(node, list): for item in node: walk(item) with open('deep.json') as f: data = json.load(f) walk(data)
This works, but it is a blunt instrument. Raising the limit does not increase available memory; it only delays the point at which Python stops you. If the recursion is genuinely too deep, the C stack will eventually overflow, causing a segmentation fault that cannot be caught.
Why Raising the Limit Can Be Dangerous
The default limit of 1000 is conservative. CPython's C stack is typically a few megabytes, and each Python frame consumes a few hundred bytes of C stack space. Raising the limit to, say, 100000 does not guarantee that the C stack can handle it. On some platforms, especially with small thread stacks, the process may crash before Python's own limit is reached.
Threads are a particular concern. The main thread often has a large stack, but worker threads created with threading.Thread may have a smaller stack size. If you set a high recursion limit and then run recursive code in a thread, you may trigger a segmentation fault instead of a RecursionError. The threading.stack_size() function can adjust thread stack size, but it must be called before creating the thread.
For these reasons, raising the limit is best reserved for controlled situations where you know the maximum depth and have verified that the platform can handle it. For general-purpose code, prefer iterative algorithms.
Recursive vs Iterative: When to Convert
Most recursive algorithms have an iterative equivalent. Converting to iteration eliminates the recursion limit entirely and gives you explicit control over memory usage. The classic example is factorial:
def factorial_recursive(n): if n <= 1: return 1 return n * factorial_recursive(n - 1) def factorial_iterative(n): result = 1 for i in range(2, n + 1): result *= i return result
For tree traversal, recursion is natural, but you can use an explicit stack:
def traverse_iterative(root): stack = [root] while stack: node = stack.pop() print(node.value) stack.extend(node.children)
The iterative version uses a list as a stack, which grows in heap memory rather than the C stack. This is safer and often easier to reason about when depth is unbounded.
Tail Recursion and Python's Behavior
Some languages optimize tail-recursive calls, reusing the current stack frame. Python does not. A function that is tail-recursive in a functional language still consumes one stack frame per call in Python. There is no tail-call optimization in CPython, and it is unlikely to be added because it complicates stack traces and debugging.
Consider a tail-recursive sum:
def sum_recursive(n, acc=0): if n == 0: return acc return sum_recursive(n - 1, acc + n)
Even though the recursive call is the last operation, Python still adds a new frame. At n=1000, this raises RecursionError just like any other recursion. Do not assume that converting to a tail-recursive style will help; you must convert to iteration or use a different approach.
Practical Example: Deep Tree Traversal
Suppose you have a binary tree that can be 5000 levels deep. A recursive depth-first search will hit the default limit quickly. You have two options: raise the limit or use an explicit stack.
Raising the limit:
import sys sys.setrecursionlimit(10000) def dfs_recursive(node): if node is None: return dfs_recursive(node.left) dfs_recursive(node.right)
This works if the tree depth is known and the C stack can handle it. But if the tree is built from untrusted input, the depth could be arbitrary, and raising the limit to a fixed value is not a robust solution.
An iterative version handles any depth:
def dfs_iterative(root): stack = [root] while stack: node = stack.pop() if node is None: continue # process node stack.append(node.right) stack.append(node.left)
The iterative version uses heap memory for the stack, which is limited by available RAM rather than a fixed interpreter setting. This is the preferred approach for production code that must handle unpredictable input depths.
Performance and Memory Considerations
Recursive calls have overhead beyond the stack limit. Each call allocates a frame, which includes local variables and bookkeeping. Iterative loops avoid that per-call allocation. For algorithms that are naturally recursive, the difference is often negligible, but for tight loops or very deep recursion, iteration is faster and uses less memory.
That said, recursion can be more readable for certain problems, like tree traversal or divide-and-conquer algorithms. The tradeoff is between clarity and robustness. If you know the maximum depth is small—say, under a few hundred—recursion is fine. If the depth is unbounded, iteration is the safer engineering choice.
When you do raise the recursion limit, be aware that it affects the entire process. If you are writing a library, changing sys.setrecursionlimit is a global side effect that can surprise other code. Avoid doing it in library code unless absolutely necessary, and document the change clearly.
Choosing the Right Approach for Your Code
The decision to use recursion or iteration should be based on the actual constraints of your problem. If the recursion depth is bounded by a known small value, recursion is acceptable. If the depth depends on user input, file content, or network data, assume it can be arbitrarily large and use an iterative approach.
For cases where recursion is the clearest expression, but the depth might exceed the default limit, consider using an explicit stack with a loop. This keeps the logic similar to recursion while avoiding the interpreter's limit. For example, a recursive tree walk can be rewritten with a stack in a few lines, and it is easier to debug because the stack is a visible data structure.
Finally, remember that sys.setrecursionlimit is a global setting. Changing it in one part of your application affects all threads and all recursive calls. Use it sparingly, and prefer to structure your algorithms so that they do not depend on an artificially high limit. The python recursion limit exists to protect the interpreter; overriding it without understanding the consequences can lead to hard crashes that are far worse than a catchable RecursionError.