error python
Python RecursionError
Understanding Python RecursionError - raised when the maximum recursion depth is exceeded, usually indicating infinite recursion.
What It Means
RecursionError is raised when the maximum recursion depth is exceeded. Python has a default recursion limit (usually 1000) to prevent stack overflow crashes. This error almost always indicates infinite or unbounded recursion — a function calling itself without a proper base case.
Common Causes
- Missing or incorrect base case in a recursive function
- Infinite recursion due to logic errors
- Circular
__repr__,__str__, or__eq__methods - Circular property access
- Recursive data structures being serialized
- Accidental recursion from overridden methods calling themselves
How to Fix
Add a proper base case
# Bad: no base case
def factorial(n):
return n * factorial(n - 1) # Never stops!
# Good: add a base case
def factorial(n):
if n <= 1:
return 1
return n * factorial(n - 1)
Convert to iteration
# Recursive version (risky for large inputs)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# Iterative version (no recursion limit)
def fibonacci(n):
if n <= 1:
return n
a, b = 0, 1
for _ in range(2, n + 1):
a, b = b, a + b
return b
# Recursive tree traversal → iterative with a stack
def traverse_iterative(root):
stack = [root]
while stack:
node = stack.pop()
process(node)
stack.extend(node.children)
Fix circular method calls
# Bad: __repr__ calls itself indirectly
class Node:
def __init__(self, value, parent=None):
self.value = value
self.parent = parent
def __repr__(self):
return f"Node({self.value}, parent={self.parent})" # Infinite loop!
# Good: avoid circular references in __repr__
class Node:
def __repr__(self):
parent_val = self.parent.value if self.parent else None
return f"Node({self.value}, parent_value={parent_val})"
Fix accidental recursion in property setters
# Bad: property setter calls itself
class User:
@property
def name(self):
return self.name # Calls the property getter again!
@name.setter
def name(self, value):
self.name = value # Calls the setter again!
# Good: use a private attribute
class User:
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
Increase recursion limit (use sparingly)
import sys
# Check current limit
print(sys.getrecursionlimit()) # Default: 1000
# Increase limit (use with caution)
sys.setrecursionlimit(5000)
# Note: this doesn't increase the actual stack size
# For very deep recursion, also increase the thread stack size:
import threading
threading.stack_size(67108864) # 64MB stack
Use memoization to reduce recursion depth
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# Now fibonacci(1000) works without hitting the recursion limit
# because previously computed values are cached
Tail recursion workaround
# Python doesn't optimize tail recursion, but you can convert manually
# Recursive:
def sum_list(lst, acc=0):
if not lst:
return acc
return sum_list(lst[1:], acc + lst[0]) # RecursionError for large lists
# Iterative equivalent:
def sum_list(lst):
acc = 0
for item in lst:
acc += item
return acc
Related Errors
- Python TypeError - Sometimes seen alongside recursion issues when types mismatch during recursive calls.
- Python AttributeError - Can result from circular attribute access patterns.