问题
The default behavior for the JSON encoder is to convert NaNs to 'NaN', e.g. json.dumps(np.NaN) results in 'NaN'. How can I change this 'NaN' value to 'null'?
I have tried to subclass the JSONEncoder and implement the default() method as follows:
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]}'
EXPECTED RESULT: '{"a": 1, "c": 3, "b": 2, "e": null, "f": [1, null, 3]}'
回答1:
This seems to achieve my objective:
import simplejson
>>> simplejson.dumps(d, ignore_nan=True)
Out[3]: '{"a": 1, "c": 3, "b": 2, "e": null, "f": [1, null, 3]}'
回答2:
Unfortunately, you probably need to use @Bramar's suggestion. You're not going to be able to use this directly. The documentation for Python's JSON encoder states:
If specified, default is a function that gets called for objects that can’t otherwise be serialized
Your NanConverter.default
method isn't even being called, since Python's JSON encoder already knows how to serialize np.nan
. Add some print statements - you'll see your method isn't even being called.
回答3:
As @Gerrat points out, your hook
dumps(d, cls=NanConverter)
unfortunately won't work.@Alexander's
simplejson.dumps(d, ignore_nan=True)
works but introduces an additional dependency (simplejson
).
If we introduce another dependency (pandas):
Another obvious solution would be
dumps(pd.DataFrame(d).fillna(None))
, but Pandas issue 1972 notes thatd.fillna(None)
will have unpredictable behaviour:Note that
fillna(None)
is equivalent tofillna()
, which means the value parameter is unused. Instead, it uses the method parameter which is by default forward fill.So instead, use
DataFrame.where
:df = pd.DataFrame(d) dumps(df.where(pd.notnull(df), None)))
回答4:
simplejson will do the right work here, but there's one extra flag worth including:
Try using simplejson:
pip install simplejson
Then in the code:
import simplejson
response = df.to_dict('records')
simplejson.dumps(response, ignore_nan=True,default=datetime.datetime.isoformat)
The ignore_nan flag will handle correctly all NaN --> null conversions
The default flag will allow simplejson to parse your datetimes correctly.
来源:https://stackoverflow.com/questions/28639953/python-nan-json-encoder