J'écris du code pour recevoir un objet arbitraire (éventuellement imbriqué) capable d'être converti en JSON.
Le comportement par défaut de l'encodeur JSON intégré de Python est de convertir les NaN en NaN
, par exemple json.dumps(np.NaN)
résulte en NaN
. Comment puis-je changer cette valeur NaN
en 'null'
?
J'ai essayé de sous-classe JSONEncoder
et de remplacer la méthode default()
comme suit:
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]}'
RÉSULTAT ATTENDU: '{"a": 1, "c": 3, "b": 2, "e": null, "f": [1, null, 3]}'
Cela semble atteindre mon objectif:
import simplejson
>>> simplejson.dumps(d, ignore_nan=True)
Out[3]: '{"a": 1, "c": 3, "b": 2, "e": null, "f": [1, null, 3]}'
Malheureusement, vous devez probablement utiliser la suggestion de @ Bramar. Vous ne pourrez pas l'utiliser directement. La documentation pour l'encodeur JSON de Python indique:
Si spécifié, la valeur par défaut est une fonction qui est appelée pour les objets qui ne peuvent pas autrement être sérialisés
Votre NanConverter.default
la méthode n'est même pas appelée, car l'encodeur JSON de Python sait déjà comment sérialiser np.nan
. Ajoutez des instructions d'impression - vous verrez que votre méthode n'est même pas appelée.
Comme le souligne @Gerrat, votre hook dumps(d, cls=NanConverter)
ne fonctionnera malheureusement pas.
La fonction simplejson.dumps(d, ignore_nan=True)
d'Alexandre fonctionne mais introduit une dépendance supplémentaire (simplejson
).
Si nous introduisons une autre dépendance (pandas):
Une autre solution évidente serait dumps(pd.DataFrame(d).fillna(None))
, mais Pandas issue 1972 note que d.fillna(None)
aura un comportement imprévisible:
Notez que
fillna(None)
est équivalent àfillna()
, ce qui signifie que le paramètre de valeur n'est pas utilisé. Au lieu de cela, il utilise le paramètre de méthode qui est par défaut le remplissage direct.
Donc, utilisez plutôt DataFrame.where
:
df = pd.DataFrame(d)
dumps(df.where(pd.notnull(df), None)))
Si vous travaillez avec pandas
:
df = df.replace({pd.np.nan: None})
Le mérite revient à ce gars ici sur problème Github .
simplejson fera le bon travail ici, mais il y a un indicateur supplémentaire qui vaut la peine d'être inclus:
Essayez d'utiliser simplejson:
pip install simplejson
Puis dans le code:
import simplejson
response = df.to_dict('records')
simplejson.dumps(response, ignore_nan=True,default=datetime.datetime.isoformat)
L'indicateur ignore_nan gérera correctement toutes les conversions NaN -> null
Le drapeau par défaut permettra à simplejson d'analyser correctement vos heures de données.