В ходе работы над
Mapfeatureserver
наступил на грабли. Не работает
сериализация в JSON, говорит,
типа
File "c:\d\Python27\lib\json\encoder.py", line 178, in default TypeError: Decimal('0E-11') is not JSON serializable
После разборок выяснилось,
что проблем аж две: стандартная библиотека
json
не умеет работать с типом данных
decimal.Decimal;
в тестовой БД поля типа numeric
(из которых и появляется питонячий
Decimal) содержат «0.0» вместо
NULL.
Еще неизвестно, какая
проблема тяжелее. Замена null-ов
на 0 произошла где-то в цепочке загрузки
данных Esri gdb → shp → PostGIS. Скорее
всего при выгрузке в шейп. Это означает,
что в перспективе надо писать загрузчик
данных напрямую из Esri gdb сразу
в PostGIS. Узелок на память.
Проблема с сериализацией
Decimal в JSON тоже
не из легких.
Есть модуль simplejson,
который понимает Decimal и
ловко с ним работает.
Например так:
data = {'a': 'b', 'c': decimal.Decimal(3.14), 'd': decimal.Decimal('0E-11')} text = simplejson.dumps(data, ensure_ascii=False, sort_keys=True, indent=2, use_decimal=True) print text.encode(CP)
что дает такой результат :
{ "a": "b", "c": 3.140000000000000124344978758017532527446746826171875, "d": 0E-11 }
Или так:
data = {'a': 'b', 'c': decimal.Decimal(3.14), 'd': decimal.Decimal('0E-11')} def jsonify(obj): if isinstance(obj, decimal.Decimal): return float(obj) raise TypeError(repr(obj) + " is not JSON serializable") text = simplejson.dumps(data, ensure_ascii=False, sort_keys=True, indent=2, default=jsonify, use_decimal=False) print text.encode(CP)
что дает несколько другой результат:
{ "a": "b", "c": 3.14, "d": 0.0 }
В принципе работает, а
вот в кожухе фигня получается. Почему?
Потому, что это выходит не сериализация,
в том смысле, что она необратима. При
применении опции «use_decimal=True»
все числа с плавающей точкой будут
загружены (функция simplejson.loads)
как Decimal. Если же
«use_decimal=False», есть шанс,
что некоторые числа вообще не загрузятся
а если загрузятся, то с потерей точности
и их тип будет НЕ Decimal. А
если сделать свой сериализатор для типа
Decimal, то на выходе dumps
будет не совсем JSON. А
все почему? Потому что числа с плавающей
точкой представлены двумя типами, в то
время как их запись текстом одна и та
же: «xyz.abc».
Что же делать? Зависит
от конкретного применения. Лично меня
устроил вариант с приведением всех
Decimal к float.
Комментариев нет:
Отправить комментарий