Python изменить представление с плавающей запятой

Хорошо, я хочу использовать repr() для вывода текстовой версии набора списков и вложенных массивов.

Но я хочу, чтобы числа имели только 4 знака после запятой: не 42,7635745114, а 32,7635.

Я хотел бы использовать repr() из-за его хорошей способности обрабатывать вложенные массивы. Написание собственного цикла печати — непривлекательный вариант.

Наверняка есть способ перегрузить repr для этого? Я вижу, что есть модули repr и reprlib, но примеров очень мало, как будто их нет.


person user3734586    schedule 12.06.2014    source источник
comment
repr следует использовать только, когда вам нужно точное строковое представление. Обычно верно, что eval(repr(x)) == x. str следует использовать для получения стандартного удобочитаемого представления. Если вам нужно настраиваемое форматирование, вы должны использовать операции форматирования (например, str.format) и указать, как должен быть составлен вывод.   -  person Bakuriu    schedule 12.06.2014
comment
Не уверен, насколько хорошо это будет работать, но вы можете попробовать создать свой собственный подкласс float с другим представлением и создать его экземпляр при создании своих данных.   -  person robbie_c    schedule 12.06.2014


Ответы (2)


Нет, перегрузить repr() невозможно. Формат чисел с плавающей запятой жестко запрограммирован в исходном коде C.

float_repr() функция вызывает вспомогательную функцию с 'r' formatter, который в конечном итоге вызывает служебную функцию, жестко кодирующую формат к тому, что сводится к format(float, '.16g').

Вы можете подклассировать float, но делать это только для представления значений (особенно в более крупной структуре) - это излишество. Именно здесь появляется repr (reprlib в Python 3); эта библиотека предназначена для печати полезных представлений произвольных структур данных и позволяет вам подключаться к печати определенных типов в этой структуре.

Вы можете использовать модуль repr, создав подкласс repr.Repr(), предоставляя repr_float() метод для обработки поплавков:

try:  # Python 3
    import reprlib
except ImportError:  # Python 2
    import repr as reprlib

class FloatRepr(reprlib.Repr):
    def repr_float(self, value, level):
        return format(value, '.4f')

print(FloatRepr().repr(object_to_represent))

Демо:

>>> import random
>>> import reprlib
>>> class FloatRepr(reprlib.Repr):
...     def repr_float(self, value, level):
...         return format(value, '.4f')
... 
>>> print(FloatRepr().repr([random.random() for _ in range(5)]))
[0.5613, 0.9042, 0.3891, 0.7396, 0.0140]

Вы можете установить атрибуты max* в своем подклассе, чтобы влиять на количество печатаемых значений для каждого типа контейнера.

person Martijn Pieters    schedule 12.06.2014
comment
Что об этом ? - person Terrence Brannon; 11.04.2017
comment
@TerrenceBrannon: этот ответ был ответом на часть пример с reprlib. Использование FloatRep устраняет необходимость создания подкласса float везде во вложенной структуре только для обеспечения нормального вывода на печать. Да, вы можете подклассировать float, но сохранять его как объект float во всех выражениях сложно (множество переопределений магических методов, и даже тогда некоторые операции будут их игнорировать), а в более крупной вложенной структуре это утомительно. - person Martijn Pieters; 11.04.2017
comment
Стоит отметить, что модуль reprlib накладывает ограничения на максимальную длину различных представлений (maxdict, maxstring и т. д.), что может удивить тех, кто ожидает достоверную замену repr. - person jpc; 09.10.2019
comment
@jpc: это самое первое, что отмечено на странице документации модуля: Модуль reprlib предоставляет средства для создания представлений объектов с ограничениями на размер результирующих строк.. Иными словами, весь пункт reprlib состоит в установлении ограничений. - person Martijn Pieters; 10.10.2019
comment
@jpc: что касается предлагаемого редактирования: я всегда рад предоставить уровень совместимости между версиями в своих ответах, просто спросите в комментарии. В 2014 году Python 2 все еще был доминирующей версией, и я написал слишком много ответов, чтобы обновлять их все. Я внимательно отношусь к тому, как я перемещаю ответы, чтобы они были ориентированы на Python 3, а не на Python 2. - person Martijn Pieters; 10.10.2019
comment
Ограничение размера, которое я указал, ни в коем случае не было критикой вашего ответа, просто то, что меня удивило. Что касается редактирования - я старался быть неинвазивным. Но в итоге меня все устраивает, ваш вариант лучше. :) - person jpc; 12.10.2019

Возможно, вы могли бы попробовать форматирование строки, используя return "%.4f" %(self.float):

>>> class obj:
...     def __init__(self, value):
...             self.float = value
...     def __repr__(self):
...             return "%.4f" %(self.float)
... 
>>> x = obj(8.1231231253252)
>>> x.float
8.1231231253252
>>> x
8.1231
>>> 
person A.J. Uppal    schedule 12.06.2014
comment
Вы меняете представление данных. Если OP использует вложенные массивы с плавающей запятой, ему придется изменить все функции, использующие такие массивы, для развертывания и повторного переноса значений. Было бы проще просто использовать подкласс float с другой реализацией __repr__. Однако я считаю, что вы всегда должны дважды подумать, прежде чем создавать подклассы для встроенных... определения только __repr__ недостаточно, поскольку каждая операция будет продолжать возвращать встроенный тип float (таким образом, нарушая вывод). - person Bakuriu; 12.06.2014