В руководстве подробно описывается создание на Python процесса JSON-сериализации, способного обрабатывать пользовательские типы данных, терпимо относиться к некорректным данным и адаптироваться к изменениям схем. Цель — передавать наборы данных между файлами, процессами, микросервисами и API без остановки конвейера при первой же аномалии.
Согласно статье, лишь небольшая часть времени инженера по машинному обучению уходит на написание архитектуры модели. Остальное приходится на «data plumbing», то есть очистку, предобработку и преобразование данных. Часть этой работы заключается в сериализации данных, преобразовании их в текст для хранения или передачи, а затем в их десериализации, то есть восстановлении в объекты Python.
Исходная проблема заключается в ограничениях формата JSON, который знает лишь несколько базовых типов. Словарь конфигурации эксперимента, содержащий Enum, set, Path или datetime, вызывает ошибку при вызове json.dumps() с сообщением «TypeError: Object of type ModelType is not JSON serializable».
Пользовательский кодировщик
Первый шаг — определить класс, который наследует от json.JSONEncoder и переопределяет его метод default(). Для каждого проблемного типа условие вида isinstance() указывает преобразование для выполнения. Так, datetime преобразуются в словарь, содержащий значение в формате ISO, set — в списки, Path — в строки, а Enum — в их значение.
Одна деталь играет ключевую роль: кодировщик добавляет ключ «__type__» к объектам, которые могут потерять свою исходную природу, например, set, преобразованный в список. После передачи в json.dumps() через аргумент cls примерный словарь сериализуется без ошибки, и datetime отображается в виде «2026-09-28T14:26:10.328310».
Устойчивый к ошибкам декодер
В обратном направлении функция robust_decoder передается в json.loads() через аргумент object_hook. Она вызывается для каждого вложенного словаря и восстанавливает исходный объект при наличии ключа «__type__». Преобразования помещаются в блок try, который перехватывает ошибки ValueError и TypeError.
В случае некорректных данных функция записывает предупреждение через модуль logging и возвращает исходное значение, не прерывая обработку. В статье уточняется, что это поведение можно заменить на значение по умолчанию или специальный словарь ошибок. После десериализации дата корректно распознается как datetime, а список — как set.
Управление изменениями схем
Схемы метаданных моделей часто меняются: добавляются или удаляются гиперпараметры, переименовываются метрики. Чтобы справиться с этим, автор предлагает фабричную функцию load_experiment_config(), которая загружает JSON с помощью декодера, а затем применяет значения по умолчанию с помощью get().
Пример касается гиперпараметра «learning_rate», отсутствующего в старой конфигурации, которому присваивается значение по умолчанию 0.001. Тот же принцип может быть применен к любому новому параметру. В статье также упоминается возможность удаления устаревших полей при загрузке. Примененная к исходной конфигурации, загрузка возвращает ожидаемые типы: целое число для идентификатора, set для переменных, PosixPath для пути, datetime для временной метки и число с плавающей точкой для скорости обучения.
