#Что произошло и когда проявляется ошибка
RecursionError при обработке вложенного JSON возникает, когда рекурсивная функция уходит слишком глубоко, структура данных необычно вложена или сериализатор встречает циклические ссылки внутри объекта Python.
#Причины и диагностические признаки
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Слишком глубоко вложенные структурыРекурсивная функция превышает ограничение глубины вызовов. | Проблема проявляется только на больших цепочках массивов и объектов | Перейти на явный стек обхода и ограничивать глубину входных данных. |
| Ошибка в базовом условии рекурсииРекурсивная функция никогда не останавливается на простом значении. | На небольшом JSON функция вызывается снова и снова | Добавить верный базовый случай и тесты. |
| Циклическая структура в памятиОбычный JSON циклов не имеет, но созданный в Python словарь может ссылаться на себя. | Ошибка возникает при повторной сериализации модифицированного объекта | Не создавать циклы; использовать штатную проверку циклов сериализатора. |
#Подробная пошаговая диагностика и исправление
- 1. Найдите точный этап исключенияПосмотрите traceback: проблема при
json.load,json.dumpsили в собственной функции, обходящей документ? Эти случаи требуют разных исправлений. Сохраните обезличенную уменьшенную копию входа и зафиксируйте размер и глубину; не публикуйте содержимое приватного JSON.
- 2. Проверьте работу на минимальном вложенном примереВ отдельном тестовом файле создайте простой словарь и последовательно увеличивайте глубину только до безопасного уровня, чтобы увидеть момент нарушения. Не поднимайте
sys.setrecursionlimitдо произвольного большого числа: это может завершить процесс из-за переполнения стека. - Пример кода по темеPythonОбразец кода для файла .py в тестовой копии проекта; перед внедрением замените имена файлов на реальные.
import json data = {"items": [{"value": 1}]} print(json.dumps(data, ensure_ascii=False))
- 3. Для собственного обхода используйте явный стекЕсли задача — обойти все элементы JSON, замените рекурсивные вызовы на цикл со стеком. Пример считает словари и списки, не копируя вложенные значения. Для данных извне обязательно добавьте максимальные размеры и предел глубины на уровне входного формата.
- Пример кода по темеPythonОбразец кода для файла .py в тестовой копии проекта; перед внедрением замените имена файлов на реальные.
def count_containers(root): stack = [root] count = 0 while stack: obj = stack.pop() if isinstance(obj, dict): count += 1 stack.extend(obj.values()) elif isinstance(obj, list): count += 1 stack.extend(obj) return count print(count_containers({"a": [1, {"b": 2}]}))
- 4. Не скрывайте циклы в Python-объектахЕсли сериализуете словарь, который ссылается на самого себя, стандартный
json.dumpsобычно выдаётValueError: Circular reference detected, а не обязательноRecursionError. Уберите обратную ссылку либо сохраняйте идентификаторы вместо полных объектов; не выключайтеcheck_circularради обхода проверки.
- 5. Сравните результат на ограниченной выборкеСначала запустите исправленный код на коротком JSON с известным результатом, затем на обезличенной копии проблемного документа. Проверьте число найденных элементов и время/память; для внешних файлов ограничьте максимальную глубину и размер до обработки.
#Как проверить, что проблема устранена
Обработка вложенного JSON завершается без бесконечной рекурсии, сохраняет ожидаемую структуру и работает в заданных ресурсных ограничениях.
#Если исправление не помогло
Если RecursionError возникает непосредственно в стандартном json.loads на экстремальной глубине, решайте вопрос с форматом или пределом вложенности входа, а не только с пользовательским обходом. Глубокие документы могут быть атакой на ресурсы.