Ответ 1
Это, похоже, достигает моей цели:
import simplejson
>>> simplejson.dumps(d, ignore_nan=True)
Out[3]: '{"a": 1, "c": 3, "b": 2, "e": null, "f": [1, null, 3]}'
Поведение по умолчанию для кодера JSON заключается в преобразовании NaN в "NaN" , например. json.dumps(np.NaN) приводит к "NaN" . Как я могу изменить это значение "NaN" на "null"?
Я попытался подклассифицировать JSONEncoder и реализовать метод default() следующим образом:
from json import JSONEncoder, dumps
import numpy as np
class NanConverter(JSONEncoder):
def default(self, obj):
try:
_ = iter(obj)
except TypeError:
if isinstance(obj, float) and np.isnan(obj):
return "null"
return JSONEncoder.default(self, obj)
>>> d = {'a': 1, 'b': 2, 'c': 3, 'e': np.nan, 'f': [1, np.nan, 3]}
>>> dumps(d, cls=NanConverter)
'{"a": 1, "c": 3, "b": 2, "e": NaN, "f": [1, NaN, 3]}'
ОЖИДАЕМЫЙ РЕЗУЛЬТАТ: '{ "a": 1, "c": 3, "b": 2, "e": null, "f": [1, null, 3]}'
Это, похоже, достигает моей цели:
import simplejson
>>> simplejson.dumps(d, ignore_nan=True)
Out[3]: '{"a": 1, "c": 3, "b": 2, "e": null, "f": [1, null, 3]}'
К сожалению, вам, вероятно, нужно использовать предложение @Bramar. Вы не сможете использовать это напрямую. Документация для кодера Python JSON гласит:
Если указано, по умолчанию это функция, которая вызывается для объектов, которые иначе не могут быть сериализованы.
Ваш метод NanConverter.default
даже не вызывается, поскольку кодер JSON Python уже знает, как сериализовать np.nan
. Добавьте несколько операторов печати - вы увидите, что ваш метод даже не вызывается.
Как указывает @Gerrat, ваш крюк dumps(d, cls=NanConverter)
, к сожалению, не будет работать.
@Alexander simplejson.dumps(d, ignore_nan=True)
работает, но вводит дополнительную зависимость (simplejson
).
Если ввести другую зависимость (pandas):
Другим очевидным решением будет dumps(pd.DataFrame(d).fillna(None))
, но Pandas issue 1972 отмечает, что d.fillna(None)
будет иметь непредсказуемое поведение:
Обратите внимание, что
fillna(None)
эквивалентноfillna()
, что означает, что параметр значения не используется. Вместо этого он использует параметр метода, который по умолчанию является прямым заполнением.
Вместо этого используйте DataFrame.where
:
df = pd.DataFrame(d)
dumps(df.where(pd.notnull(df), None)))
simplejson выполнит правильную работу здесь, но есть еще один дополнительный флаг, включая:
Попробуйте использовать simplejson:
pip install simplejson
Затем в коде:
import simplejson
response = df.to_dict('records')
simplejson.dumps(response, ignore_nan=True,default=datetime.datetime.isoformat)
Флаг ignore_nan будет корректно обрабатывать все преобразования NaN → null
По умолчанию флаг позволяет simplejson правильно анализировать ваши даты.
Если вы работаете с pandas
:
df = df.replace({pd.np.nan: None})
Это заслуга этого парня в вопросе Github.