Search code examples
pythonfloating-pointpython-3.xsubclassbuilt-in-types

subclassing float to force fixed point printing precision in python


[Python 3.1]

I'm following up on this answer:

class prettyfloat(float):
  def __repr__(self):
    return "%0.2f" % self

I know I need to keep track of my float literals (i.e., replace 3.0 with prettyfloat(3.0), etc.), and that's fine.

But whenever I do any calculations, prettyfloat objects get converted into float.

What's the easiest way to fix it?

EDIT:

I need exactly two decimal digits; and I need it across the whole code, including where I print a dictionary with float values inside. That makes any formatting functions hard to use.

I can't use Decimal global setting, since I want computations to be at full precision (just printing at 2 decimal points).

@Glenn Maynard: I agree I shouldn't override __repr__; if anything, it would be just __str__. But it's a moot point because of the following point.

@Glenn Maynard and @singularity: I won't subclass float, since I agree it will look very ugly in the end.

I will stop trying to be clever, and just call a function everywhere a float is being printed. Though I am really sad that I can't override __str__ in the builtin class float.

Thank you!


Solution

  • I had a look at the answer you followed up on, and I think you're confusing data and its representation.

    @Robert Rossney suggested to subclass float so you could map() an iterable of standard, non-adulterated floats into prettyfloats for display purposes:

    # Perform all our computations using standard floats.
    results = compute_huge_numbers(42)
    # Switch to prettyfloats for printing.
    print(map(prettyfloat, results))
    

    In other words, you were not supposed to (and you shouldn't) use prettyfloat as a replacement for float everywhere in your code.

    Of course, inheriting from float to solve that problem is overkill, since it's a representation problem and not a data problem. A simple function would be enough:

    def prettyfloat(number):
        return "%0.2f" % number  # Works the same.
    

    Now, if it's not about representation after all, and what you actually want to achieve is fixed-point computations limited to two decimal places everywhere in your code, that's another story entirely.