Кодер Python NaN JSON

Поведение по умолчанию для кодера 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]}'

Ответ 1

Это, похоже, достигает моей цели:

import simplejson


>>> simplejson.dumps(d, ignore_nan=True)
Out[3]: '{"a": 1, "c": 3, "b": 2, "e": null, "f": [1, null, 3]}'

Ответ 2

К сожалению, вам, вероятно, нужно использовать предложение @Bramar. Вы не сможете использовать это напрямую. Документация для кодера Python JSON гласит:

Если указано, по умолчанию это функция, которая вызывается для объектов, которые иначе не могут быть сериализованы.

Ваш метод NanConverter.default даже не вызывается, поскольку кодер JSON Python уже знает, как сериализовать np.nan. Добавьте несколько операторов печати - вы увидите, что ваш метод даже не вызывается.

Ответ 3

  • Как указывает @Gerrat, ваш крюк dumps(d, cls=NanConverter), к сожалению, не будет работать.

  • @Alexander simplejson.dumps(d, ignore_nan=True) работает, но вводит дополнительную зависимость (simplejson).

Если ввести другую зависимость (pandas):

  1. Другим очевидным решением будет dumps(pd.DataFrame(d).fillna(None)), но Pandas issue 1972 отмечает, что d.fillna(None) будет иметь непредсказуемое поведение:

    Обратите внимание, что fillna(None) эквивалентно fillna(), что означает, что параметр значения не используется. Вместо этого он использует параметр метода, который по умолчанию является прямым заполнением.

  2. Вместо этого используйте DataFrame.where:

    df = pd.DataFrame(d)
    dumps(df.where(pd.notnull(df), None)))
    

Ответ 4

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 правильно анализировать ваши даты.

Ответ 5

Если вы работаете с pandas:

df = df.replace({pd.np.nan: None})

Это заслуга этого парня в вопросе Github.