Say I have this (all this is Python 3.11 in case that matters):
not_a_number = float("NaN") # this actually comes from somewhere else
json.encode([not_a_number])
The output is an (invalid) JSON literal NaN. I've been trying to create an JSONEncoder subclass that would use math.isnan() to determine if the value is a NaN and output None instead.
I first tried subclassing JSONEncoder and doing it in default(), which I found later isn't called for things like float. I then found a recommendation to override the encode() method instead, so I tried this:
class NanEncoder(json.JSONEncoder):
def encode(self, obj):
if isinstance(obj, float):
if math.isnan(obj):
return None
return super(NanEncoder, self).encode(obj)
This works:
>>> json.dumps(not_a_number, cls=NanEncoder)
>>> json_string = json.dumps(not_a_number, cls=NanEncoder)
>>> print(json_string)
None
Cool, I think I've got it. BUT, this does not work:
not_a_number_list = [not_a_number]
print(not_a_number_list)
[nan]
json_string = json.dumps(not_a_number_list, cls=NanEncoder)
print(json_string)
[NaN]
So, as I see in the python docs, maybe I need to call the encode method slightly differently, so I try that:
json_string = NanEncoder().encode(not_a_number_list)
print(json_string)
[NaN]
Alas, no difference.
So, here's my question: is it possible to create a JSONEncoder subclass that will find instances of the float that is NaN in Python and output None instead? Or am I relegated to do a search/replace on the string NaN with null in the output JSON (which, theoretically anyway, could alter data I don't want to)? Fixing the input dictionary is not a great option because the dict that the values are in is quite large and it's construction is not under my control (so I can't stop NaN from getting in there in the first place).
I don't know about easy solution to replace
NaNwith custom values (other than replaceNaNs in original object).On top of that,
jsonmodule doesn't make it easy to monkeypatch the inner workings: https://github.com/python/cpython/blob/034bb70aaad5622bd53bad21595b18b8f4407984/Lib/json/encoder.py#L224But you can try:
Prints: