J'utilise le module json standard en python 2.6 pour sérialiser une liste de flotteurs. Cependant, j'obtiens des résultats comme celui-ci:
>>> import json
>>> json.dumps([23.67, 23.97, 23.87])
'[23.670000000000002, 23.969999999999999, 23.870000000000001]'
Je veux que les flotteurs soient formatés avec seulement deux chiffres décimaux. La sortie devrait ressembler à ceci:
>>> json.dumps([23.67, 23.97, 23.87])
'[23.67, 23.97, 23.87]'
J'ai essayé de définir ma propre classe d'encodeur JSON:
class MyEncoder(json.JSONEncoder):
def encode(self, obj):
if isinstance(obj, float):
return format(obj, '.2f')
return json.JSONEncoder.encode(self, obj)
Cela fonctionne pour un seul objet flottant:
>>> json.dumps(23.67, cls=MyEncoder)
'23.67'
Mais échoue pour les objets imbriqués:
>>> json.dumps([23.67, 23.97, 23.87])
'[23.670000000000002, 23.969999999999999, 23.870000000000001]'
Je ne veux pas de dépendances externes, donc je préfère m'en tenir au module json standard.
Comment puis-je atteindre cet objectif?
la source
original_float_repr = encoder.FLOAT_REPR
encoder.FLOAT_REPR = lambda o: format(o, '.2f')
print json.dumps(1.0001)
encoder.FLOAT_REPR = original_float_repr
23.67
voir en quoi.2f
n'est pas respecté.émet
Aucun monkeypatching nécessaire.
la source
pretty_floats
fonction et l' ai simplement intégrée dans mon autre code.list( map(pretty_floats, obj) )
map
renvoie l'itérateur, pas unlist
Si vous utilisez Python 2.7, une solution simple consiste simplement à arrondir explicitement vos flottants à la précision souhaitée.
Cela fonctionne parce que Python 2.7 a rendu l' arrondi flottant plus cohérent . Malheureusement, cela ne fonctionne pas dans Python 2.6:
Les solutions mentionnées ci-dessus sont des solutions de contournement pour 2.6, mais aucune n'est entièrement adéquate. Monkey patching json.encoder.FLOAT_REPR ne fonctionne pas si votre environnement d'exécution Python utilise une version C du module JSON. La classe PrettyFloat dans la réponse de Tom Wuttke fonctionne, mais seulement si l'encodage% g fonctionne globalement pour votre application. Le% .15g est un peu magique, cela fonctionne car la précision du flotteur est de 17 chiffres significatifs et% g n'imprime pas les zéros de fin.
J'ai passé du temps à essayer de faire un PrettyFloat qui permettait de personnaliser la précision de chaque nombre. Ie, une syntaxe comme
Ce n'est pas facile de bien faire les choses. Hériter de float est gênant. Hériter d'Object et utiliser une sous-classe JSONEncoder avec sa propre méthode default () devrait fonctionner, sauf que le module json semble supposer que tous les types personnalisés doivent être sérialisés sous forme de chaînes. Ie: vous vous retrouvez avec la chaîne Javascript "0.33" dans la sortie, pas le nombre 0.33. Il existe peut-être encore un moyen de faire en sorte que cela fonctionne, mais c'est plus difficile qu'il n'y paraît.
la source
Vraiment dommage qui
dumps
ne vous permet pas de faire quoi que ce soit pour les flotteurs. Mais leloads
fait. Donc, si cela ne vous dérange pas la charge supplémentaire du processeur, vous pouvez le lancer à travers l'encodeur / décodeur / encodeur et obtenir le bon résultat:la source
parse_float
kwarg!Voici une solution qui a fonctionné pour moi dans Python 3 et qui ne nécessite pas de patch monkey:
La sortie est:
Il copie les données mais avec des flottants arrondis.
la source
Si vous êtes bloqué avec Python 2.5 ou des versions antérieures: L'astuce monkey-patch ne semble pas fonctionner avec le module simplejson d'origine si les accélérations C sont installées:
la source
Vous pouvez faire ce que vous devez faire, mais ce n'est pas documenté:
la source
FLOAT_REPR
constante dans lejson.encoder
module.La solution d'Alex Martelli fonctionnera pour les applications à thread unique, mais peut ne pas fonctionner pour les applications multithreads qui doivent contrôler le nombre de décimales par thread. Voici une solution qui devrait fonctionner dans les applications multi-threadées:
Vous pouvez simplement définir encoder.thread_local.decimal_places sur le nombre de décimales souhaité, et le prochain appel à json.dumps () dans ce thread utilisera ce nombre de décimales
la source
Si vous avez besoin de le faire en python 2.7 sans remplacer le json.encoder.FLOAT_REPR global, voici une solution.
Ensuite, en python 2.7:
En python 2.6, cela ne fonctionne pas tout à fait comme le souligne Matthew Schinckel ci-dessous:
la source
Avantages:
Les inconvénients:
Complexité quadratique.
la source
Lors de l'importation du module json standard, il suffit de changer le codeur par défaut FLOAT_REPR. Il n'est pas vraiment nécessaire d'importer ou de créer des instances Encoder.
Parfois, il est également très utile de générer en json la meilleure représentation que python peut deviner avec str. Cela garantira que les chiffres significatifs ne sont pas ignorés.
la source
Je suis d'accord avec @Nelson pour dire qu'hériter de float est gênant, mais peut-être qu'une solution qui ne touche que la
__repr__
fonction pourrait être pardonnable. J'ai fini par utiliser ledecimal
package pour reformater les flotteurs en cas de besoin. L'avantage est que cela fonctionne dans tous les contextes où ilrepr()
est appelé, donc également lors de l'impression de listes sur stdout par exemple. En outre, la précision est configurable à l'exécution, une fois les données créées. L'inconvénient est bien sûr que vos données doivent être converties dans cette classe flottante spéciale (car malheureusement, vous ne pouvez pas sembler monkey patchfloat.__repr__
). Pour cela, je propose une brève fonction de conversion.Le code:
Exemple d'utilisation:
la source
Utilisation de numpy
Si vous avez de très longs flotteurs, vous pouvez les arrondir correctement avec numpy:
'[23.67, 23.97, 23.87]'
la source
Je viens de publier fjson , une petite bibliothèque Python pour résoudre ce problème. Installer avec
et utilisez juste comme
json
, avec l'ajout dufloat_format
paramètre:la source