Формат плавает с помощью стандартного модуля JSON - PullRequest
81 голосов
/ 19 сентября 2009

Я использую стандартный json модуль в Python 2.6 для сериализации списка чисел с плавающей запятой. Тем не менее, я получаю такие результаты:

>>> import json
>>> json.dumps([23.67, 23.97, 23.87])
'[23.670000000000002, 23.969999999999999, 23.870000000000001]'

Я хочу, чтобы числа с плавающей запятой форматировались только с двумя десятичными цифрами. Вывод должен выглядеть так:

>>> json.dumps([23.67, 23.97, 23.87])
'[23.67, 23.97, 23.87]'

Я попытался определить свой собственный класс JSON Encoder:

class MyEncoder(json.JSONEncoder):
    def encode(self, obj):
        if isinstance(obj, float):
            return format(obj, '.2f')
        return json.JSONEncoder.encode(self, obj)

Это работает для единственного объекта с плавающей точкой:

>>> json.dumps(23.67, cls=MyEncoder)
'23.67'

Но не работает для вложенных объектов:

>>> json.dumps([23.67, 23.97, 23.87])
'[23.670000000000002, 23.969999999999999, 23.870000000000001]'

Я не хочу иметь внешние зависимости, поэтому я предпочитаю придерживаться стандартного модуля json.

Как мне этого добиться?

Ответы [ 12 ]

1 голос
/ 30 апреля 2014

При импорте стандартного модуля json достаточно изменить кодер по умолчанию FLOAT_REPR. Нет необходимости импортировать или создавать экземпляры кодировщика.

import json
json.encoder.FLOAT_REPR = lambda o: format(o, '.2f')

json.dumps([23.67, 23.97, 23.87]) #returns  '[23.67, 23.97, 23.87]'

Иногда также очень полезно выводить, поскольку json лучший питон представления может угадать с помощью str. Это обеспечит игнорирование значащих цифр.

import json
json.dumps([23.67, 23.9779, 23.87489])
# output is'[23.670000000000002, 23.977900000000002, 23.874890000000001]'

json.encoder.FLOAT_REPR = str
json.dumps([23.67, 23.9779, 23.87489])
# output is '[23.67, 23.9779, 23.87489]'
1 голос
/ 20 марта 2012

Плюсы:

  • Работает с любым кодировщиком JSON или даже с представителем Python.
  • Short (ish), похоже, работает.

Минусы:

  • Уродливый хак регулярных выражений, только что протестированный.
  • Квадратичная сложность.

    def fix_floats(json, decimals=2, quote='"'):
        pattern = r'^((?:(?:"(?:\\.|[^\\"])*?")|[^"])*?)(-?\d+\.\d{'+str(decimals)+'}\d+)'
        pattern = re.sub('"', quote, pattern) 
        fmt = "%%.%df" % decimals
        n = 1
        while n:
            json, n = re.subn(pattern, lambda m: m.group(1)+(fmt % float(m.group(2)).rstrip('0')), json)
        return json
    
...