Как улучшить работу со словарём с неизвестной структурой в Python?
Что проверяют
Умеете ли вы безопасно достать данные из вложенного JSON, где ключей может не быть, а типы плавают, и понимаете ли, когда защитный код пора заменить явной схемой. Следом часто просят написать функцию, которая достаёт значение по пути вроде user.address.city.
Как отвечать
- одиночный доступ:
d.get("key", default)вместоd["key"]. Помните, что значение по умолчанию подставится только при отсутствии ключа: если ключ есть со значениемNone, вернётсяNone; - вложенность: цепочка
d.get("a", {}).get("b")ломается, если на промежуточном уровне пришёлNoneили список. Надёжнее маленькая функция, которая идёт по пути и проверяетisinstance(node, dict)на каждом шаге, либоtry/except (KeyError, TypeError, IndexError)вокруг прямого доступа; - разбор по форме:
matchс шаблонами словаря (Python 3.10+) проверяет структуру и сразу достаёт значения:case {"user": {"id": int(uid)}}. Лишние ключи шаблон игнорирует; - накопление:
defaultdict(list)иsetdefaultудобны, когда вы строите словарь, а не читаете чужой. При чтенииdefaultdictопасен: обращение к отсутствующему ключу молча его создаёт; - схема на границе: если структура в целом известна, валидировать данные один раз на входе через
pydanticv2 (Model.model_validate(data)) или описатьTypedDictдля проверки типов. Дальше код работает с объектом и не проверяет каждый ключ; - совсем произвольные данные: рекурсивный обход с проверкой на
dictиlist, а для запросов по путям библиотеки вродеglomилиjmespath.
Производительность здесь редко главная тема: доступ по ключу стоит O(1) в среднем, и тормозит обычно не словарь, а повторный разбор JSON и лишние копии.
Где спотыкаются
Оборачивают весь блок в try/except Exception: pass. Ошибка структуры исчезает, а в данных оказываются молча пропущенные поля.
Путают d.get("x") or default и d.get("x", default). Первый вариант заменит и законные 0, "" и False.
Пишут десяток уровней .get(..., {}) вместо того, чтобы один раз описать схему. Такой код тяжело читать, и он всё равно падает на неожиданном типе.