El error RecursionError en Python aparece cuando una función se llama a sí misma demasiadas veces sin alcanzar una condición de salida. El mensaje habitual es maximum recursion depth exceeded. En la mayoría de los casos, la solución correcta consiste en corregir el caso base, reducir la profundidad o sustituir la recursión por una estructura iterativa.
Aumentar el límite con sys.setrecursionlimit() puede ser apropiado en situaciones controladas, pero no debe utilizarse para ocultar una función que nunca termina.
Ejemplo de recursión infinita
def countdown(number):
print(number)
return countdown(number - 1)
countdown(5)La función continúa después de llegar a cero porque no existe un caso base. Finalmente Python detiene la ejecución para proteger la pila.
La documentación oficial de RecursionError describe esta excepción como el resultado de superar la profundidad máxima del intérprete.
Añadir un caso base
def countdown(number):
if number <= 0:
print("Fin")
return
print(number)
countdown(number - 1)
countdown(5)El caso base debe detener todas las rutas posibles. No basta con escribir una condición que ciertos datos nunca alcanzan.
Comprobar que el problema se acerca al caso base
Una función recursiva correcta reduce o transforma el problema:
def factorial(number):
if number < 0:
raise ValueError(
"El factorial requiere un entero no negativo"
)
if number in {0, 1}:
return 1
return number * factorial(number - 1)Cada llamada utiliza number - 1, por lo que eventualmente llega a 1.
La guía de funciones en Python explica parámetros, retornos, validación y scope.
Error por una actualización incorrecta
def search(values, index=0):
if index >= len(values):
return None
if values[index] == "target":
return index
return search(values, index)El índice no cambia, por lo que la función repite el mismo estado. Corrige la llamada:
return search(values, index + 1)Registrar o imprimir los argumentos de cada llamada ayuda a detectar estados repetidos.
Recursión mutua
El ciclo puede involucrar varias funciones:
def is_even(number):
return is_odd(number - 1)
def is_odd(number):
return is_even(number - 1)Sin casos base, ambas funciones se llaman indefinidamente. Una corrección sería:
def is_even(number):
if number == 0:
return True
return is_odd(abs(number) - 1)
def is_odd(number):
if number == 0:
return False
return is_even(abs(number) - 1)Para este problema concreto, number % 2 == 0 es mucho más simple. No utilices recursión cuando una expresión directa resuelve la tarea.
Consultar el límite actual
import sys
print(sys.getrecursionlimit())El valor suele estar alrededor de mil llamadas, pero depende de la implementación y configuración.
La documentación oficial de getrecursionlimit() explica que el límite evita una recursión infinita que desborde la pila de C.
Aumentar el límite con precaución
import sys
sys.setrecursionlimit(2000)Un valor demasiado alto puede provocar un cierre del intérprete o agotar la memoria. Solo aumenta el límite cuando:
- el algoritmo tiene un caso base correcto;
- la profundidad máxima es conocida;
- los datos realmente requieren ese nivel;
- se han probado alternativas iterativas;
- el entorno soporta el cambio.
Convertir una función a un bucle
Un countdown no necesita recursión:
def countdown(number):
while number > 0:
print(number)
number -= 1
print("Fin")El bucle utiliza memoria constante y admite valores grandes. La guía de bucles en Python explica iteración, range(), break y continue.
Recorrer un árbol con una pila explícita
Una función recursiva para recorrer nodos puede fallar en árboles muy profundos:
def traverse(node):
print(node.value)
for child in node.children:
traverse(child)Versión iterativa:
def traverse(root):
stack = [root]
while stack:
node = stack.pop()
print(node.value)
stack.extend(reversed(node.children))La lista funciona como una pila y evita depender de la pila de llamadas.
Recorrer un grafo sin ciclos infinitos
En grafos, además de la profundidad, debes controlar nodos visitados:
def visit(graph, start):
visited = set()
stack = [start]
while stack:
node = stack.pop()
if node in visited:
continue
visited.add(node)
stack.extend(graph.get(node, []))
return visitedSin visited, un ciclo como A → B → A provoca llamadas repetidas. La guía de sets en Python explica pruebas de pertenencia eficientes.
Memoización para cálculos repetidos
Una función puede terminar correctamente, pero repetir demasiado trabajo:
def fibonacci(number):
if number < 2:
return number
return (
fibonacci(number - 1)
+ fibonacci(number - 2)
)Utiliza caché:
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(number):
if number < 2:
return number
return (
fibonacci(number - 1)
+ fibonacci(number - 2)
)La memoización reduce llamadas repetidas, pero no elimina la profundidad lineal. Para números grandes, una versión iterativa sigue siendo más segura.
Versión iterativa de Fibonacci
def fibonacci(number):
if number < 0:
raise ValueError(
"El número debe ser no negativo"
)
previous = 0
current = 1
for _ in range(number):
previous, current = current, previous + current
return previousEsta versión utiliza memoria constante y no puede superar el límite de recursión.
Procesar JSON o estructuras anidadas
Datos externos pueden contener una profundidad inesperada. Una función recursiva debe validar la estructura:
def count_values(data, depth=0, max_depth=100):
if depth > max_depth:
raise ValueError(
"La estructura supera la profundidad permitida"
)
if isinstance(data, dict):
return sum(
count_values(value, depth + 1, max_depth)
for value in data.values()
)
if isinstance(data, list):
return sum(
count_values(value, depth + 1, max_depth)
for value in data
)
return 1Limitar la profundidad también protege servicios que procesan datos no confiables.
Capturar RecursionError
try:
result = process_structure(data)
except RecursionError as error:
raise ValueError(
"La estructura es demasiado profunda"
) from errorCapturar la excepción puede mejorar el mensaje en una frontera de la aplicación, pero no reemplaza la corrección del algoritmo.
La guía de try y except en Python explica encadenamiento y manejo por capas.
Depurar la profundidad
def recursive_function(value, depth=0):
print(" " * depth, value)
if is_finished(value):
return value
next_value = transform(value)
return recursive_function(
next_value,
depth + 1,
)Comprueba si next_value cambia realmente. También puedes utilizar breakpoints, logging o cProfile para observar llamadas repetidas.
La guía de cProfile en Python ayuda a detectar funciones llamadas demasiadas veces.
Recursión de cola
Python no aplica optimización general de tail calls. Incluso cuando la llamada recursiva es la última operación, cada llamada conserva un frame:
def factorial(number, accumulator=1):
if number <= 1:
return accumulator
return factorial(
number - 1,
accumulator * number,
)Para profundidades grandes, convierte este patrón a un bucle.
Ejemplo completo de diagnóstico
def safe_countdown(number):
if not isinstance(number, int):
raise TypeError("Se requiere un entero")
if number < 0:
raise ValueError(
"El número no puede ser negativo"
)
while number:
print(number)
number -= 1
print("Fin")La versión valida la entrada y evita por completo la profundidad recursiva.
Procedimiento recomendado
- Localiza la función repetida en el traceback.
- Comprueba el caso base.
- Verifica que cada llamada avance hacia él.
- Busca ciclos entre varias funciones o nodos.
- Prueba una versión iterativa.
- Añade memoización si existe trabajo repetido.
- Aumenta el límite solamente con una profundidad conocida.
Errores frecuentes
- Aumentar el límite antes de revisar el caso base.
- Modificar un argumento sin acercarlo a la salida.
- Recorrer grafos sin registrar visitados.
- Usar recursión para una repetición lineal simple.
- Suponer que Python optimiza recursión de cola.
- Confundir memoización con reducción de profundidad.
- Capturar RecursionError y continuar con un resultado incompleto.
Conclusión
RecursionError casi siempre indica que el algoritmo no termina o que la profundidad supera lo razonable para la pila. Corrige primero el caso base y el progreso de los argumentos. Para listas largas, árboles profundos o grafos, utiliza una pila explícita o un bucle. Modifica el límite únicamente cuando el algoritmo sea correcto y la profundidad esté controlada.






