Форматирование Python больших значений

Ниже приведен код форматирования значения x, которое я использовал.

Примеры того, что он делает:

  • Он составляет 7 500 000 в 7,5 М
  • Он форматирует 800 000 в 800 К Это

    def Formatting(self, x, pos):
        formats = ((1e-12,'%d%s T','%1.1f T'),
                   (1e-9, '%d%s B','%1.1f B'),
                   (1e-6, '%d%s M','%1.1f M'),
                   (1e-3, '%d%s k','%1.1f K'  ))
    
        for i, (N, A, B) in enumerate(formats):
            if abs(x) > (1./N):
                result = ''
                x = x * N
    
                if abs(x) >= 1000:
                    x, r = divmod(x, 1000)
                    result = ",%03d%s" % (r, result)
                    return A % (x, result)
    
                else: return B % (x)
    
    
            elif 1   <= abs(x) < 1e3: return '%1.0f' % (x)
            elif 0.1 <= abs(x) < 1:   return '%1.1f' % (x)
            elif 0   <  abs(x) < 0.1: return '%1.3f' % (x)
            elif x == 0:              return '%1.0f' % (x)
    

Теперь я изо всех сил стараюсь сделать следующие улучшения:

  • Вместо 550 M я хотел бы иметь возможность печатать .55 B
  • Вместо 550 B я хотел бы иметь возможность печатать .55 T
  • Вместо 550 K я хотел бы иметь возможность печатать .55 M
  • Вместо 0,001 я хотел бы иметь возможность печатать .001 без нулевого
  • Однако 55,5 М, 55,5 В, 55,5 К все равно должны быть напечатаны - не .055 М, или .055 В..

Предложения о том, как выполнить это изменение или улучшить этот фрагмент кода, чтобы иметь более значимые распечатки (которые используются в диаграмме)?

Большое спасибо!

Ответ 1

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

Поскольку у вас был метод, я включил его в класс. (Это также позволяет избежать определения formats каждый раз, когда вызывается функция.)

from math import log10

class Formatter(object):
    def __init__(self):
        self.formats = (('%1.1f', 0),
                        ('%2.1f', 0),
                        ('%1.2f K', 3),
                        ('%1.2f K', 3),
                        ('%2.1f K', 3),
                        ('%1.2f M', 6),
                        ('%1.2f M', 6),
                        ('%2.1f M', 6),
                        ('%1.2f B', 9),
                        ('%1.2f B', 9),
                        ('%2.1f B', 9),
                        ('%1.2f T', 12),
                        ('%1.2f T', 12),
                        ('%2.1f T', 12))

    def human_readable(self, x):
        if x == 0: return '0'
        magnitude = int(log10(abs(x)))
        if magnitude > 13: format_str, denominator_mag = '%i T', 12
        else: format_str, denominator_mag = self.formats[magnitude]
        return (format_str % (x * 1.0 / (10 ** denominator_mag))).lstrip('0')

Изменить: здесь, который не использует таблицу поиска:

def human_readable(self, x):
    if x == 0: return '0'
    magnitude = int(log10(abs(x)))
    if magnitude > 13: 
        format_str = '%i T'
        denominator_mag = 12
    else: 
        float_fmt = '%2.1f ' if magnitude % 3 == 1 else '%1.2f '
        illion = (magnitude + 1) // 3
        format_str = float_fmt + ['', 'K', 'M', 'B', 'T'][illion]
        denominator_mag = illion * 3
    return (format_str % (x * 1.0 / (10 ** denominator_mag))).lstrip('0')

Ответ 2

Попробуйте все возможные способы его форматирования и выберите кратчайший по длине с предпочтением больших единиц (например, от 55 до 550 М, поскольку они имеют одинаковую длину).

Как для удаления ведущих нулей, одно из возможных решений проверяет, если s[:2] == '0.' и заменив его на '.'