J'ai un Decimal('3.9')
dans le cadre d'un objet, et souhaite encoder cela en une chaîne JSON qui devrait ressembler à{'x': 3.9}
. Je ne me soucie pas de la précision du côté client, donc un flotteur est très bien.
Existe-t-il un bon moyen de sérialiser cela? JSONDecoder n'accepte pas les objets Decimal, et la conversion en un flottant au préalable donne {'x': 3.8999999999999999}
ce qui est faux, et sera un gros gaspillage de bande passante.
Réponses:
Qu'en est-il du sous
json.JSONEncoder
- classement ?Ensuite, utilisez-le comme ceci:
la source
DecimalEncoder()._iterencode(decimal.Decimal('3.9')).next()
retournait le bon'3.9'
, maisDecimalEncoder()._iterencode(3.9).next()
renvoyait un objet générateur qui ne reviendrait que'3.899...'
lorsque vous en empileriez un autre.next()
. Générateur d'affaires drôles. Oh bien ... Ça devrait marcher maintenant.return (str(o),)
place?[o]
est une liste avec seulement 1 élément, pourquoi se donner la peine de boucler dessus?return (str(o),)
retournerait un tuple de longueur 1, tandis que le code dans la réponse renvoie un générateur de longueur 1. Voir les documents iterencode ()Simplejson 2.1 et supérieur a un support natif pour le type décimal:
Notez que
use_decimal
c'estTrue
par défaut:Alors:
Espérons que cette fonctionnalité sera incluse dans la bibliothèque standard.
la source
json.loads(s, use_decimal=True)
vous obtenez la décimale. Aucun flotteur dans tout le processus. Modifié la réponse ci-dessus. J'espère que l'affiche originale va bien.use_decimal=True
les charges.json.dumps({'a' : Decimal('3.9')}, use_decimal=True)
donne'{"a": 3.9}'
. Le but n'était'{"a": "3.9"}'
-il pas ?simplejson.dumps(decimal.Decimal('2.2'))
fonctionne également: non expliciteuse_decimal
(testé sur simplejson / 3.6.0). Une autre façon de le recharger est:json.loads(s, parse_float=Decimal)
c'est-à-dire que vous pouvez le lire en utilisant stdlibjson
(et les anciennessimplejson
versions sont également prises en charge).Je voudrais faire savoir à tout le monde que j'ai essayé la réponse de Michał Marczyk sur mon serveur Web qui exécutait Python 2.6.5 et cela a bien fonctionné. Cependant, j'ai mis à niveau vers Python 2.7 et il a cessé de fonctionner. J'ai essayé de penser à une sorte de moyen d'encoder des objets décimaux et voici ce que j'ai trouvé:
J'espère que cela devrait aider toute personne ayant des problèmes avec Python 2.7. Je l'ai testé et cela semble bien fonctionner. Si quelqu'un remarque des bogues dans ma solution ou propose une meilleure solution, faites-le moi savoir.
la source
unicode
oustr
au lieu defloat
pour assurer la précision."54.4"
, pas en tant que un numéro.Dans mon application Flask, qui utilise python 2.7.11, l'alchimie des flacons (avec les types 'db.decimal') et Flask Marshmallow (pour le sérialiseur et désérialiseur 'instantané'), j'ai eu cette erreur, chaque fois que j'ai fait un GET ou un POST . Le sérialiseur et le désérialiseur n'ont pas réussi à convertir les types décimaux en n'importe quel format identifiable JSON.
J'ai fait un "pip install simplejson", puis juste en ajoutant
le sérialiseur et le désérialiseur recommencent à ronronner. Je n'ai rien fait d'autre ... Les DEciamls sont affichés au format flottant '234.00'.
la source
simplejson
- il suffit de l'installer pour faire l'affaire. Initialement mentionné par cette réponse .Decimal('0.00') is not JSON serializable
quand même après l'installation via pip. Cette situation se produit lorsque vous utilisez à la fois de la guimauve et du graphène. Lorsqu'une requête est appelée sur une API de repos, la guimauve fonctionne normalement pour les champs décimaux. Cependant, quand il est appelé avec graphql, il a généré uneis not JSON serializable
erreur.J'ai essayé de passer de simplejson à json intégré pour GAE 2.7 et j'ai eu des problèmes avec la décimale. Si la valeur par défaut renvoyait str (o), il y avait des guillemets (car _iterencode appelle _iterencode sur les résultats de la valeur par défaut), et float (o) supprimerait le 0 à la fin.
Si par défaut renvoie un objet d'une classe qui hérite de float (ou de tout ce qui appelle repr sans formatage supplémentaire) et possède une méthode __repr__ personnalisée, cela semble fonctionner comme je le souhaite.
la source
float.__repr__
codé en dur (qui perd en précision) etfakefloat.__repr__
n'est pas appelé du tout. La solution ci-dessus fonctionne correctement pour python3 jusqu'à 3.5.1, si fakefloat a une méthode supplémentairedef __float__(self): return self
.L'option native est manquante, je vais donc l'ajouter pour le prochain gars / gall qui le recherche.
À partir de Django 1.7.x, il existe un module intégré à partir duquel
DjangoJSONEncoder
vous pouvez l'obtenirdjango.core.serializers.json
.Presto!
la source
Mon 0,02 $!
J'étends un tas de l'encodeur JSON depuis que je sérialise des tonnes de données pour mon serveur web. Voici un bon code. Notez qu'il est facilement extensible à pratiquement tous les formats de données que vous souhaitez et reproduira 3.9 comme
"thing": 3.9
Rend ma vie tellement plus facile ...
la source
"thing": "3.9"
.3.9
ne peut pas être représenté exactement dans les flotteurs IEEE, cela viendra toujours car3.8999999999999999
, par exemple, essayezprint repr(3.9)
, vous pouvez en savoir plus à ce sujet ici:http://en.wikipedia.org/wiki/Floating_point
http://docs.sun.com/source/806-3568/ncg_goldberg.html
Donc, si vous ne voulez pas de float, seule option vous devez l'envoyer sous forme de chaîne et pour permettre la conversion automatique des objets décimaux en JSON, faites quelque chose comme ceci:
la source
json.loads("3.9")
cela fonctionnera, et j'aimerais que ce soit çaPour les utilisateurs de Django :
Récemment rencontré
TypeError: Decimal('2337.00') is not JSON serializable
lors de l'encodage JSON iejson.dumps(data)
Solution :
Mais, maintenant la valeur Decimal sera une chaîne, maintenant nous pouvons explicitement définir l'analyseur de valeur décimal / flottant lors du décodage des données, en utilisant l'
parse_float
option dansjson.loads
:la source
Du document standard JSON , comme lié dans json.org :
Il est donc exact de représenter les décimales sous forme de nombres (plutôt que de chaînes) dans JSON. Ci-dessous se trouve une solution possible au problème.
Définissez un encodeur JSON personnalisé:
Ensuite, utilisez-le lors de la sérialisation de vos données:
Comme indiqué dans les commentaires sur les autres réponses, les anciennes versions de python peuvent perturber la représentation lors de la conversion en float, mais ce n'est plus le cas.
Pour récupérer la décimale en Python:
Cette solution est suggérée dans la documentation Python 3.0 sur les décimales :
la source
float
nécessairement vous fait perdre la représentation décimale, et vous conduire à des écarts. SiDecimal
c'est important à utiliser, je pense qu'il vaut mieux utiliser des cordes.Voici ce que j'ai, extrait de notre classe
Qui passe le moins:
la source
json.loads(myString, cls=CommonJSONEncoder)
commentaire devrait êtrejson.loads(myString, cls=CommonJSONDecoder)
Vous pouvez créer un encodeur JSON personnalisé selon vos besoins.
Le décodeur peut être appelé comme ceci,
et la sortie sera:
la source
Pour ceux qui ne veulent pas utiliser une bibliothèque tierce ... Un problème avec la réponse d'Elias Zamaria est qu'elle se transforme en float, ce qui peut entraîner des problèmes. Par exemple:
La
JSONEncoder.encode()
méthode vous permet de retourner le contenu json littéral, contrairement àJSONEncoder.default()
ce qui vous oblige à retourner un type compatible json (comme float) qui est ensuite encodé de la manière normale. Le problèmeencode()
est qu'il ne fonctionne (normalement) qu'au niveau supérieur. Mais c'est toujours utilisable, avec un peu de travail supplémentaire (python 3.x):Ce qui vous donne:
la source
Sur la base de la réponse stdOrgnlDave, j'ai défini ce wrapper qu'il peut être appelé avec des types facultatifs afin que l'encodeur ne fonctionne que pour certains types à l'intérieur de vos projets. Je crois que le travail doit être fait à l'intérieur de votre code et ne pas utiliser cet encodeur "par défaut" car "il vaut mieux explicite qu'implicite", mais je comprends que son utilisation vous fera gagner du temps. :-)
la source
Si vous souhaitez passer un dictionnaire contenant des décimales à la
requests
bibliothèque (en utilisant l'json
argument mot - clé), il vous suffit d'installersimplejson
:La raison du problème est qu'il
requests
n'utilisesimplejson
que s'il est présent, et retombe sur le intégréjson
s'il n'est pas installé.la source
cela peut être fait en ajoutant
dans
\Lib\json\encoder.py:JSONEncoder._iterencode
, mais j'espérais une meilleure solutionla source