2

Okay, I want to use repr() to print out a text version of a bunch of lists and nested arrays.

But I want the numbers to have only 4 decimal places not: 42.7635745114 but 32.7635.

I'd like to use repr() because of its nice ability to handle nested arrays. Writing my own print loop is an unattractive option.

Surely there is some way to overload repr to do this? I see there is a repr and reprlib modules but examples are really scarce, like nonexistent.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
user3734586
  • 41
  • 1
  • 3
  • `repr` should be used *only* when you want a **precise** string representation. It's usually true that `eval(repr(x)) == x`. `str` should be used to obtain a *standard* readable representation. If you want a *custom formatting* you have to use the formatting operations (e.g. `str.format`) and specify how the output should be composed. – Bakuriu Jun 12 '14 at 15:07
  • Not sure how well this would work, but you could try creating your own subclass of float with a different representation, and instantiating that instead when you create your data. – robbie_c Jun 12 '14 at 15:41

2 Answers2

6

No, there is no way to overload repr(). The format for floats is hardcoded in the C source code.

The float_repr() function calls a helper function with the 'r' formatter, which eventually calls a utility function that hardcodes the format to what comes down to format(float, '.16g').

You could subclass float, but to only do that for representing values (especially in a larger structure) is overkill. This is where repr (reprlib in Python 3) comes in; that library is designed to print useful representations of arbitrary data structures, and letting you hook into printing specific types in that structure.

You could use the repr module by subclassing repr.Repr(), providing a repr_float() method to handle floats:

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))

Demo:

>>> 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]

You may want to set the max* attributes on your subclass to influence how many values are printed per container type.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • What [about this?](http://stackoverflow.com/questions/1566936/easy-pretty-printing-of-floats-in-python) – Terrence Brannon Apr 11 '17 at 02:40
  • @TerrenceBrannon: this answer was a response to the *example with reprlib* part. Using `FloatRep` removes the need to subclass `float` everywhere in a nested structure just to provide sane printed output. Yes, you can subclass `float`, but *keeping* it a `float` object throughout expressions is hard (lots of magic method overriding and even then some operations will ignore those), and in a larger nested structure, bothersome. – Martijn Pieters Apr 11 '17 at 06:34
  • It is worth noting that the `reprlib` module places limits on the maximum lengths of various representation (`maxdict`, `maxstring`, etc.) which may surprise someone expecting a faithful `repr` replacement. – jpc Oct 09 '19 at 19:31
  • @jpc: that's the *very first thing noted* on the module documentation page: *The `reprlib` module provides a means for producing object representations **with limits on the size of the resulting strings.***. Put differently, the whole *point* of `reprlib` is to place limits. – Martijn Pieters Oct 10 '19 at 16:34
  • @jpc: as for the suggested edit: I'm always happy to provide a cross-version compatibility layer in my answers, just ask in a comment. In 2014, Python 2 was still the dominant version and I wrote too many answers to update them all. I *am* somewhat particular as to how I move answers to be Python 3 focused rather than Python 2 centric. – Martijn Pieters Oct 10 '19 at 16:40
  • The size limit I pointed out was by no means a critique of your answer, just something that surprised me. As for the edit - I tried to be non-invasive. But in the end it’s ok with me, your version is better. :) – jpc Oct 12 '19 at 06:50
0

Maybe you could try string formatting using 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
>>> 
A.J. Uppal
  • 19,117
  • 6
  • 45
  • 76
  • You are changing the data representation. If the OP is using nested arrays of floats he'd have to change all the functions that use such arrays to unwrap and re-wrap the values. It would be easier to simply use a subclass of `float` with a different implementation of `__repr__`. However I believe you should always think twice before subclassing built-ins... defining *only* `__repr__` isn't enough since every operation would keep returning the built-in `float` type (thus breaking the output). – Bakuriu Jun 12 '14 at 15:10